samples: drivers: adc: add ADC example
This sample shows how to use the ADC API. Depending on the support of sequential reads in the driver, 1 or 2 channels are read and printed. A devicetree overlay is necessary to specify the used ADC channel(s). Signed-off-by: Martin Jäger <martin@libre.solar>
This commit is contained in:
parent
3c7b2771b1
commit
0520ec814b
8
samples/drivers/adc/CMakeLists.txt
Normal file
8
samples/drivers/adc/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.13.1)
|
||||
|
||||
find_package(Zephyr HINTS $ENV{ZEPHYR_BASE})
|
||||
project(ADC)
|
||||
|
||||
target_sources(app PRIVATE src/main.c)
|
61
samples/drivers/adc/README.rst
Normal file
61
samples/drivers/adc/README.rst
Normal file
|
@ -0,0 +1,61 @@
|
|||
.. _adc-sample:
|
||||
|
||||
Analog-to-Digital Converter (ADC)
|
||||
#################################
|
||||
|
||||
Overview
|
||||
********
|
||||
|
||||
This sample demonstrates how to use the ADC driver API.
|
||||
|
||||
Depending on the MCU type, it reads the ADC samples of one or two ADC channels
|
||||
and prints the readings to the console. If supported by the driver, 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.
|
||||
|
||||
.. note::
|
||||
|
||||
This sample does not work on Nordic platforms where there is a distinction
|
||||
between channel and analog input that requires additional configuration. See
|
||||
:zephyr_file:`samples/boards/nrf/battery` for an example of using the ADC
|
||||
infrastructure on Nordic hardware.
|
||||
|
||||
|
||||
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 :ref:`nucleo_l073rz_board` can be easily adjusted for other boards.
|
||||
|
||||
Building and Running for ST Nucleo L073RZ
|
||||
=========================================
|
||||
|
||||
The sample can be built and executed for the
|
||||
:ref:`nucleo_l073rz_board` as follows:
|
||||
|
||||
.. zephyr-app-commands::
|
||||
:zephyr-app: samples/drivers/adc
|
||||
: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(s): 42 (raw)
|
||||
|
||||
.. note:: If the ADC is not supported, the output will be an error message.
|
12
samples/drivers/adc/boards/nucleo_l073rz.overlay
Normal file
12
samples/drivers/adc/boards/nucleo_l073rz.overlay
Normal file
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Copyright (c) 2020 Libre Solar Technologies GmbH
|
||||
*/
|
||||
|
||||
/ {
|
||||
zephyr,user {
|
||||
/* adjust channel number according to pinmux in board.dts */
|
||||
io-channels = <&adc1 1>;
|
||||
};
|
||||
};
|
1
samples/drivers/adc/prj.conf
Normal file
1
samples/drivers/adc/prj.conf
Normal file
|
@ -0,0 +1 @@
|
|||
CONFIG_ADC=y
|
12
samples/drivers/adc/sample.yaml
Normal file
12
samples/drivers/adc/sample.yaml
Normal file
|
@ -0,0 +1,12 @@
|
|||
sample:
|
||||
name: ADC driver sample
|
||||
tests:
|
||||
sample.drivers.adc:
|
||||
tags: ADC
|
||||
depends_on: adc
|
||||
platform_allow: nucleo_l073rz
|
||||
harness: console
|
||||
harness_config:
|
||||
type: single_line
|
||||
regex:
|
||||
- "ADC reading(s): (.*)"
|
122
samples/drivers/adc/src/main.c
Normal file
122
samples/drivers/adc/src/main.c
Normal file
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Libre Solar Technologies GmbH
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <sys/printk.h>
|
||||
#include <drivers/adc.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
|
||||
|
||||
#define ADC_NUM_CHANNELS DT_PROP_LEN(DT_PATH(zephyr_user), io_channels)
|
||||
|
||||
#if ADC_NUM_CHANNELS > 2
|
||||
#error "Currently only 1 or 2 channels supported in this sample"
|
||||
#endif
|
||||
|
||||
#if ADC_NUM_CHANNELS == 2 && !DT_SAME_NODE( \
|
||||
DT_PHANDLE_BY_IDX(DT_PATH(zephyr_user), io_channels, 0), \
|
||||
DT_PHANDLE_BY_IDX(DT_PATH(zephyr_user), io_channels, 1))
|
||||
#error "Channels have to use the same ADC."
|
||||
#endif
|
||||
|
||||
#define ADC_NODE DT_PHANDLE(DT_PATH(zephyr_user), io_channels)
|
||||
|
||||
/* Common settings supported by most ADCs */
|
||||
#define ADC_RESOLUTION 12
|
||||
#define ADC_GAIN ADC_GAIN_1
|
||||
#define ADC_REFERENCE ADC_REF_INTERNAL
|
||||
#define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT
|
||||
|
||||
/* Get the numbers of up to two channels */
|
||||
static uint8_t channel_ids[ADC_NUM_CHANNELS] = {
|
||||
DT_IO_CHANNELS_INPUT_BY_IDX(DT_PATH(zephyr_user), 0),
|
||||
#if ADC_NUM_CHANNELS == 2
|
||||
DT_IO_CHANNELS_INPUT_BY_IDX(DT_PATH(zephyr_user), 1)
|
||||
#endif
|
||||
};
|
||||
|
||||
static int16_t sample_buffer[ADC_NUM_CHANNELS];
|
||||
|
||||
struct adc_channel_cfg channel_cfg = {
|
||||
.gain = ADC_GAIN,
|
||||
.reference = ADC_REFERENCE,
|
||||
.acquisition_time = ADC_ACQUISITION_TIME,
|
||||
/* channel ID will be overwritten below */
|
||||
.channel_id = 0,
|
||||
.differential = 0
|
||||
};
|
||||
|
||||
struct adc_sequence sequence = {
|
||||
/* individual channels will be added below */
|
||||
.channels = 0,
|
||||
.buffer = sample_buffer,
|
||||
/* buffer size in bytes, not number of samples */
|
||||
.buffer_size = sizeof(sample_buffer),
|
||||
.resolution = ADC_RESOLUTION,
|
||||
};
|
||||
|
||||
void main(void)
|
||||
{
|
||||
int err;
|
||||
const struct device *dev_adc = DEVICE_DT_GET(ADC_NODE);
|
||||
|
||||
if (!device_is_ready(dev_adc)) {
|
||||
printk("ADC device not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure channels individually prior to sampling
|
||||
*/
|
||||
for (uint8_t i = 0; i < ADC_NUM_CHANNELS; i++) {
|
||||
channel_cfg.channel_id = channel_ids[i];
|
||||
#ifdef CONFIG_ADC_NRFX_SAADC
|
||||
channel_cfg.input_positive = SAADC_CH_PSELP_PSELP_AnalogInput0
|
||||
+ channel_ids[i];
|
||||
#endif
|
||||
|
||||
adc_channel_setup(dev_adc, &channel_cfg);
|
||||
|
||||
sequence.channels |= BIT(channel_ids[i]);
|
||||
}
|
||||
|
||||
int32_t adc_vref = adc_ref_internal(dev_adc);
|
||||
|
||||
while (1) {
|
||||
/*
|
||||
* Read sequence of channels (fails if not supported by MCU)
|
||||
*/
|
||||
err = adc_read(dev_adc, &sequence);
|
||||
if (err != 0) {
|
||||
printk("ADC reading failed with error %d.\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("ADC reading(s):");
|
||||
for (uint8_t i = 0; i < ADC_NUM_CHANNELS; i++) {
|
||||
int32_t raw_value = sample_buffer[i];
|
||||
|
||||
printk(" %d", raw_value);
|
||||
if (adc_vref > 0) {
|
||||
/*
|
||||
* Convert raw reading to millivolts if driver
|
||||
* supports reading of ADC reference voltage
|
||||
*/
|
||||
int32_t mv_value = raw_value;
|
||||
|
||||
adc_raw_to_millivolts(adc_vref, ADC_GAIN,
|
||||
ADC_RESOLUTION, &mv_value);
|
||||
printk(" = %d mV ", mv_value);
|
||||
}
|
||||
}
|
||||
printk("\n");
|
||||
|
||||
k_sleep(K_MSEC(1000));
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue