Working DT ADC sample WITHOUT resistor divider
This commit is contained in:
parent
2c21f1f9cb
commit
dcb73c0a25
|
|
@ -0,0 +1,8 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(ADC)
|
||||
|
||||
target_sources(app PRIVATE src/main.c)
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
.. zephyr:code-sample:: adc_dt
|
||||
:name: Analog-to-Digital Converter (ADC) with devicetree
|
||||
:relevant-api: adc_interface
|
||||
|
||||
Read analog inputs from ADC channels.
|
||||
|
||||
Overview
|
||||
********
|
||||
|
||||
This sample demonstrates how to use the :ref:`ADC driver API <adc_api>`.
|
||||
|
||||
Depending on the target board, it reads ADC samples from one or more channels
|
||||
and prints the readings on the console. If voltage of the used reference can
|
||||
be obtained, the raw readings are converted to millivolts.
|
||||
|
||||
The pins of the ADC channels are board-specific. Please refer to the board
|
||||
or MCU datasheet for further details.
|
||||
|
||||
Building and Running
|
||||
********************
|
||||
|
||||
The ADC peripheral and pinmux is configured in the board's ``.dts`` file. Make
|
||||
sure that the ADC is enabled (``status = "okay";``).
|
||||
|
||||
In addition to that, this sample requires an ADC channel specified in the
|
||||
``io-channels`` property of the ``zephyr,user`` node. This is usually done with
|
||||
a devicetree overlay. The example overlay in the ``boards`` subdirectory for
|
||||
the ``nucleo_l073rz`` board can be easily adjusted for other boards.
|
||||
|
||||
Configuration of channels (settings like gain, reference, or acquisition time)
|
||||
also needs to be specified in devicetree, in ADC controller child nodes. Also
|
||||
the ADC resolution and oversampling setting (if used) need to be specified
|
||||
there. See :zephyr_file:`boards/nrf52840dk_nrf52840.overlay
|
||||
<samples/drivers/adc/adc_dt/boards/nrf52840dk_nrf52840.overlay>` for an example of
|
||||
such setup.
|
||||
|
||||
Building and Running for ST Nucleo L073RZ
|
||||
=========================================
|
||||
|
||||
The sample can be built and executed for the
|
||||
:zephyr:board:`nucleo_l073rz` as follows:
|
||||
|
||||
.. zephyr-app-commands::
|
||||
:zephyr-app: samples/drivers/adc/adc_dt
|
||||
:board: nucleo_l073rz
|
||||
:goals: build flash
|
||||
:compact:
|
||||
|
||||
To build for another board, change "nucleo_l073rz" above to that board's name
|
||||
and provide a corresponding devicetree overlay.
|
||||
|
||||
Sample output
|
||||
=============
|
||||
|
||||
You should get a similar output as below, repeated every second:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
ADC reading:
|
||||
- ADC_0, channel 7: 36 = 65mV
|
||||
|
||||
.. note:: If the ADC is not supported, the output will be an error message.
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
/{
|
||||
/ {
|
||||
zephyr,user {
|
||||
io-channels = <&adc1 1>, <&adc1 12>;
|
||||
io-channels = <&adc1 1>;
|
||||
io-channel-names = "multi_sense";
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -16,19 +17,12 @@
|
|||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
channel@1 {
|
||||
/* This defines channel 1 on adc1. The "1" in io-channels refers to this reg value. */
|
||||
adc_channel_1: channel@1 {
|
||||
reg = <1>;
|
||||
zephyr,gain = "ADC_GAIN_1";
|
||||
zephyr,reference = "ADC_REF_INTERNAL";
|
||||
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
||||
zephyr,resolution = <12>;
|
||||
};
|
||||
|
||||
channel@c {
|
||||
reg = <0xc>;
|
||||
zephyr,gain = "ADC_GAIN_1";
|
||||
zephyr,reference = "ADC_REF_INTERNAL";
|
||||
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
||||
zephyr,resolution = <12>;
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
CONFIG_ADC=y
|
||||
CONFIG_LOG=y
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
sample:
|
||||
name: ADC devicetree driver sample
|
||||
tests:
|
||||
sample.drivers.adc.adc_dt:
|
||||
tags:
|
||||
- adc
|
||||
depends_on: adc
|
||||
platform_allow:
|
||||
- nucleo_l073rz
|
||||
- disco_l475_iot1
|
||||
- cc3220sf_launchxl
|
||||
- cc3235sf_launchxl
|
||||
- cy8cproto_063_ble
|
||||
- stm32l496g_disco
|
||||
- stm32h735g_disco
|
||||
- nrf51dk/nrf51822
|
||||
- nrf52840dk/nrf52840
|
||||
- nrf54l15dk/nrf54l15/cpuapp
|
||||
- nrf54h20dk/nrf54h20/cpuapp
|
||||
- ophelia4ev/nrf54l15/cpuapp
|
||||
- mec172xevb_assy6906
|
||||
- gd32f350r_eval
|
||||
- gd32f450i_eval
|
||||
- gd32vf103v_eval
|
||||
- gd32f403z_eval
|
||||
- esp32_devkitc/esp32/procpu
|
||||
- esp32s2_saola
|
||||
- esp32c3_devkitm
|
||||
- gd32l233r_eval
|
||||
- lpcxpresso55s36
|
||||
- mr_canhubk3
|
||||
- longan_nano
|
||||
- longan_nano/gd32vf103/lite
|
||||
- rd_rw612_bga
|
||||
- frdm_mcxn947/mcxn947/cpu0
|
||||
- mcx_n9xx_evk/mcxn947/cpu0
|
||||
- frdm_mcxc242
|
||||
- ucans32k1sic
|
||||
- xg24_rb4187c
|
||||
- xg29_rb4412a
|
||||
- raytac_an54l15q_db/nrf54l15/cpuapp
|
||||
- frdm_mcxa166
|
||||
- frdm_mcxa276
|
||||
integration_platforms:
|
||||
- nucleo_l073rz
|
||||
- nrf52840dk/nrf52840
|
||||
harness: console
|
||||
timeout: 10
|
||||
harness_config:
|
||||
type: multi_line
|
||||
regex:
|
||||
- "ADC reading\\[\\d+\\]:"
|
||||
- "- .+, channel \\d+: -?\\d+"
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Wolter HV <wolterhv@gmx.de>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/ {
|
||||
zephyr,user {
|
||||
io-channels = <&adc0 0>;
|
||||
};
|
||||
};
|
||||
|
||||
&adc0 {
|
||||
status = "okay";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
channel@0 {
|
||||
reg = <0>;
|
||||
zephyr,gain = "ADC_GAIN_1_4";
|
||||
zephyr,reference = "ADC_REF_INTERNAL";
|
||||
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
||||
zephyr,resolution = <12>;
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Wolter HV <wolterhv@gmx.de>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/ {
|
||||
zephyr,user {
|
||||
io-channels = <&adc0 0>;
|
||||
};
|
||||
};
|
||||
|
||||
&adc0 {
|
||||
status = "okay";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
channel@0 {
|
||||
reg = <0>;
|
||||
zephyr,gain = "ADC_GAIN_1_4";
|
||||
zephyr,reference = "ADC_REF_INTERNAL";
|
||||
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
||||
zephyr,resolution = <12>;
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Wolter HV <wolterhv@gmx.de>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/ {
|
||||
zephyr,user {
|
||||
io-channels = <&adc0 0>;
|
||||
};
|
||||
};
|
||||
|
||||
&adc0 {
|
||||
status = "okay";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
channel@0 {
|
||||
reg = <0>;
|
||||
zephyr,gain = "ADC_GAIN_1_4";
|
||||
zephyr,reference = "ADC_REF_INTERNAL";
|
||||
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
||||
zephyr,resolution = <12>;
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Wolter HV <wolterhv@gmx.de>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/ {
|
||||
zephyr,user {
|
||||
io-channels = <&adc0 0>;
|
||||
};
|
||||
};
|
||||
|
||||
&adc0 {
|
||||
status = "okay";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
channel@0 {
|
||||
reg = <0>;
|
||||
zephyr,gain = "ADC_GAIN_1_4";
|
||||
zephyr,reference = "ADC_REF_INTERNAL";
|
||||
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
||||
zephyr,resolution = <12>;
|
||||
};
|
||||
};
|
||||
|
|
@ -1,101 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Libre Solar Technologies GmbH
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/devicetree.h>
|
||||
#include <zephyr/drivers/adc.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/sys/printk.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#if !DT_NODE_EXISTS(DT_PATH(zephyr_user)) || \
|
||||
!DT_NODE_HAS_PROP(DT_PATH(zephyr_user), io_channels)
|
||||
#error "No suitable devicetree overlay specified"
|
||||
#endif
|
||||
LOG_MODULE_REGISTER(adc_dt_example, LOG_LEVEL_DBG);
|
||||
|
||||
#define DT_SPEC_AND_COMMA(node_id, prop, idx) \
|
||||
ADC_DT_SPEC_GET_BY_IDX(node_id, idx),
|
||||
|
||||
/* Data of ADC io-channels specified in devicetree. */
|
||||
static const struct adc_dt_spec adc_channels[] = {
|
||||
DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), io_channels,
|
||||
DT_SPEC_AND_COMMA)
|
||||
};
|
||||
/* Get the ADC channel specification from the devicetree */
|
||||
#define SENSE_NODE DT_PATH(zephyr_user)
|
||||
static const struct adc_dt_spec sense_channel = ADC_DT_SPEC_GET_BY_NAME(SENSE_NODE, multi_sense);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int err;
|
||||
uint32_t count = 0;
|
||||
uint16_t buf;
|
||||
struct adc_sequence sequence = {
|
||||
.buffer = &buf,
|
||||
/* buffer size in bytes, not number of samples */
|
||||
.buffer_size = sizeof(buf),
|
||||
};
|
||||
|
||||
/* Configure channels individually prior to sampling. */
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(adc_channels); i++) {
|
||||
if (!adc_is_ready_dt(&adc_channels[i])) {
|
||||
printk("ADC controller device %s not ready\n", adc_channels[i].dev->name);
|
||||
if (!device_is_ready(sense_channel.dev)) {
|
||||
LOG_ERR("ADC controller device not ready");
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = adc_channel_setup_dt(&adc_channels[i]);
|
||||
err = adc_channel_setup_dt(&sense_channel);
|
||||
if (err < 0) {
|
||||
printk("Could not setup channel #%d (%d)\n", i, err);
|
||||
LOG_ERR("Could not setup channel #%u (%d)", sense_channel.channel_id, err);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CONFIG_COVERAGE
|
||||
LOG_INF("ADC channel setup successful!");
|
||||
|
||||
while (1) {
|
||||
#else
|
||||
for (int k = 0; k < 10; k++) {
|
||||
#endif
|
||||
printk("ADC reading[%u]:\n", count++);
|
||||
for (size_t i = 0U; i < ARRAY_SIZE(adc_channels); i++) {
|
||||
int32_t val_mv;
|
||||
// 1. Explicitly initialize the sequence structure from the devicetree spec.
|
||||
// This sets sequence.channels correctly.
|
||||
(void)adc_sequence_init_dt(&sense_channel, &sequence);
|
||||
|
||||
printk("- %s, channel %d: ",
|
||||
adc_channels[i].dev->name,
|
||||
adc_channels[i].channel_id);
|
||||
|
||||
(void)adc_sequence_init_dt(&adc_channels[i], &sequence);
|
||||
|
||||
err = adc_read_dt(&adc_channels[i], &sequence);
|
||||
// 2. Perform the read on the ADC device with the now-configured sequence.
|
||||
err = adc_read(sense_channel.dev, &sequence);
|
||||
if (err < 0) {
|
||||
printk("Could not read (%d)\n", err);
|
||||
LOG_ERR("Could not read (%d)", err);
|
||||
k_sleep(K_MSEC(1000));
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* If using differential mode, the 16 bit value
|
||||
* in the ADC sample buffer should be a signed 2's
|
||||
* complement value.
|
||||
*/
|
||||
if (adc_channels[i].channel_cfg.differential) {
|
||||
val_mv = (int32_t)((int16_t)buf);
|
||||
} else {
|
||||
val_mv = (int32_t)buf;
|
||||
}
|
||||
printk("%"PRId32, val_mv);
|
||||
err = adc_raw_to_millivolts_dt(&adc_channels[i],
|
||||
&val_mv);
|
||||
/* conversion to mV may not be supported, skip if not */
|
||||
int32_t val_mv = buf;
|
||||
err = adc_raw_to_millivolts_dt(&sense_channel, &val_mv);
|
||||
if (err < 0) {
|
||||
printk(" (value in mV not available)\n");
|
||||
} else {
|
||||
printk(" = %"PRId32" mV\n", val_mv);
|
||||
}
|
||||
LOG_WRN("Could not convert to millivolts (%d)", err);
|
||||
}
|
||||
|
||||
LOG_INF("ADC reading raw: %d -> %d mV", buf, val_mv);
|
||||
|
||||
k_sleep(K_MSEC(1000));
|
||||
}
|
||||
return 0;
|
||||
|
|
|
|||
Loading…
Reference in New Issue