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
6 changed files with 216 additions and 0 deletions
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…
Add table
Add a link
Reference in a new issue