mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #20045 from benpicco/periph_adc_continous
periph/adc: introduce periph_adc_continuous
This commit is contained in:
commit
04617ee0a9
@ -8,6 +8,7 @@
|
|||||||
config CPU_COMMON_SAM0
|
config CPU_COMMON_SAM0
|
||||||
bool
|
bool
|
||||||
select HAS_PERIPH_CPUID
|
select HAS_PERIPH_CPUID
|
||||||
|
select HAS_PERIPH_ADC_CONTINUOUS
|
||||||
select HAS_PERIPH_FLASHPAGE
|
select HAS_PERIPH_FLASHPAGE
|
||||||
select HAS_PERIPH_FLASHPAGE_IN_ADDRESS_SPACE
|
select HAS_PERIPH_FLASHPAGE_IN_ADDRESS_SPACE
|
||||||
select HAS_PERIPH_FLASHPAGE_PAGEWISE
|
select HAS_PERIPH_FLASHPAGE_PAGEWISE
|
||||||
|
@ -7,6 +7,7 @@ ifeq (,$(filter $(CPU_MODELS_WITHOUT_DMA),$(CPU_MODEL)))
|
|||||||
FEATURES_PROVIDED += periph_dma
|
FEATURES_PROVIDED += periph_dma
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
FEATURES_PROVIDED += periph_adc_continuous
|
||||||
FEATURES_PROVIDED += periph_flashpage
|
FEATURES_PROVIDED += periph_flashpage
|
||||||
FEATURES_PROVIDED += periph_flashpage_in_address_space
|
FEATURES_PROVIDED += periph_flashpage_in_address_space
|
||||||
FEATURES_PROVIDED += periph_flashpage_pagewise
|
FEATURES_PROVIDED += periph_flashpage_pagewise
|
||||||
|
@ -49,16 +49,6 @@ static int _adc_configure(Adc *dev, adc_res_t res);
|
|||||||
|
|
||||||
static mutex_t _lock = MUTEX_INIT;
|
static mutex_t _lock = MUTEX_INIT;
|
||||||
|
|
||||||
static inline void _prep(void)
|
|
||||||
{
|
|
||||||
mutex_lock(&_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void _done(void)
|
|
||||||
{
|
|
||||||
mutex_unlock(&_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void _wait_syncbusy(Adc *dev)
|
static inline void _wait_syncbusy(Adc *dev)
|
||||||
{
|
{
|
||||||
#ifdef ADC_STATUS_SYNCBUSY
|
#ifdef ADC_STATUS_SYNCBUSY
|
||||||
@ -263,7 +253,7 @@ int adc_init(adc_t line)
|
|||||||
const uint8_t adc = 0;
|
const uint8_t adc = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_prep();
|
mutex_lock(&_lock);
|
||||||
|
|
||||||
uint8_t muxpos = (adc_channels[line].inputctrl & ADC_INPUTCTRL_MUXPOS_Msk)
|
uint8_t muxpos = (adc_channels[line].inputctrl & ADC_INPUTCTRL_MUXPOS_Msk)
|
||||||
>> ADC_INPUTCTRL_MUXPOS_Pos;
|
>> ADC_INPUTCTRL_MUXPOS_Pos;
|
||||||
@ -284,34 +274,44 @@ int adc_init(adc_t line)
|
|||||||
gpio_init_mux(sam0_adc_pins[adc][muxneg], GPIO_MUX_B);
|
gpio_init_mux(sam0_adc_pins[adc][muxneg], GPIO_MUX_B);
|
||||||
}
|
}
|
||||||
|
|
||||||
_done();
|
mutex_unlock(&_lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t adc_sample(adc_t line, adc_res_t res)
|
static Adc *_dev(adc_t line)
|
||||||
{
|
{
|
||||||
if (line >= ADC_NUMOF) {
|
|
||||||
DEBUG("adc: line arg not applicable\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The SAMD5x/SAME5x family has two ADCs: ADC0 and ADC1. */
|
/* The SAMD5x/SAME5x family has two ADCs: ADC0 and ADC1. */
|
||||||
#ifdef ADC0
|
#ifdef ADC0
|
||||||
Adc *dev = adc_channels[line].dev;
|
return adc_channels[line].dev;
|
||||||
#else
|
#else
|
||||||
Adc *dev = ADC;
|
(void)line;
|
||||||
|
return ADC;
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
bool diffmode = adc_channels[line].inputctrl & ADC_INPUTCTRL_DIFFMODE;
|
static Adc *_adc(uint8_t dev)
|
||||||
|
{
|
||||||
_prep();
|
/* The SAMD5x/SAME5x family has two ADCs: ADC0 and ADC1. */
|
||||||
|
#ifdef ADC0
|
||||||
if (_adc_configure(dev, res) != 0) {
|
switch (dev) {
|
||||||
_done();
|
case 0:
|
||||||
DEBUG("adc: configuration failed\n");
|
return ADC0;
|
||||||
return -1;
|
case 1:
|
||||||
|
return ADC1;
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
(void)dev;
|
||||||
|
return ADC;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t _sample(adc_t line)
|
||||||
|
{
|
||||||
|
Adc *dev = _dev(line);
|
||||||
|
bool diffmode = adc_channels[line].inputctrl & ADC_INPUTCTRL_DIFFMODE;
|
||||||
|
|
||||||
dev->INPUTCTRL.reg = ADC_GAIN_FACTOR_DEFAULT
|
dev->INPUTCTRL.reg = ADC_GAIN_FACTOR_DEFAULT
|
||||||
| adc_channels[line].inputctrl
|
| adc_channels[line].inputctrl
|
||||||
@ -319,7 +319,6 @@ int32_t adc_sample(adc_t line, adc_res_t res)
|
|||||||
#ifdef ADC_CTRLB_DIFFMODE
|
#ifdef ADC_CTRLB_DIFFMODE
|
||||||
dev->CTRLB.bit.DIFFMODE = diffmode;
|
dev->CTRLB.bit.DIFFMODE = diffmode;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_wait_syncbusy(dev);
|
_wait_syncbusy(dev);
|
||||||
|
|
||||||
/* Start the conversion */
|
/* Start the conversion */
|
||||||
@ -331,9 +330,6 @@ int32_t adc_sample(adc_t line, adc_res_t res)
|
|||||||
uint16_t sample = dev->RESULT.reg;
|
uint16_t sample = dev->RESULT.reg;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
_adc_poweroff(dev);
|
|
||||||
_done();
|
|
||||||
|
|
||||||
/* in differential mode we lose one bit for the sign */
|
/* in differential mode we lose one bit for the sign */
|
||||||
if (diffmode) {
|
if (diffmode) {
|
||||||
result = 2 * (int16_t)sample;
|
result = 2 * (int16_t)sample;
|
||||||
@ -341,11 +337,102 @@ int32_t adc_sample(adc_t line, adc_res_t res)
|
|||||||
result = sample;
|
result = sample;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t _shift_from_res(adc_res_t res)
|
||||||
|
{
|
||||||
/* 16 bit mode is implemented as oversampling */
|
/* 16 bit mode is implemented as oversampling */
|
||||||
if ((res & 0x3) == 1) {
|
if ((res & 0x3) == 1) {
|
||||||
/* ADC does automatic right shifts beyond 16 samples */
|
/* ADC does automatic right shifts beyond 16 samples */
|
||||||
result <<= (4 - MIN(4, res >> 2));
|
return 4 - MIN(4, res >> 2);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _get_adcs(bool *adc0, bool *adc1)
|
||||||
|
{
|
||||||
|
#ifndef ADC1
|
||||||
|
*adc0 = true;
|
||||||
|
*adc1 = false;
|
||||||
|
return;
|
||||||
|
#else
|
||||||
|
for (unsigned i = 0; i < ADC_NUMOF; ++i) {
|
||||||
|
if (adc_channels[i].dev == ADC0) {
|
||||||
|
*adc0 = true;
|
||||||
|
} else if (adc_channels[i].dev == ADC1) {
|
||||||
|
*adc1 = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t _shift;
|
||||||
|
void adc_continuous_begin(adc_res_t res)
|
||||||
|
{
|
||||||
|
bool adc0, adc1;
|
||||||
|
_get_adcs(&adc0, &adc1);
|
||||||
|
|
||||||
|
mutex_lock(&_lock);
|
||||||
|
|
||||||
|
if (adc0) {
|
||||||
|
_adc_configure(_adc(0), res);
|
||||||
|
}
|
||||||
|
if (adc1) {
|
||||||
|
_adc_configure(_adc(1), res);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
_shift = _shift_from_res(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t adc_continuous_sample(adc_t line)
|
||||||
|
{
|
||||||
|
int val;
|
||||||
|
assert(line < ADC_NUMOF);
|
||||||
|
|
||||||
|
mutex_lock(&_lock);
|
||||||
|
val = _sample(line) << _shift;
|
||||||
|
mutex_unlock(&_lock);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void adc_continuous_stop(void)
|
||||||
|
{
|
||||||
|
bool adc0, adc1;
|
||||||
|
_get_adcs(&adc0, &adc1);
|
||||||
|
|
||||||
|
if (adc0) {
|
||||||
|
_adc_poweroff(_adc(0));
|
||||||
|
}
|
||||||
|
if (adc1) {
|
||||||
|
_adc_poweroff(_adc(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t adc_sample(adc_t line, adc_res_t res)
|
||||||
|
{
|
||||||
|
if (line >= ADC_NUMOF) {
|
||||||
|
DEBUG("adc: line arg not applicable\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&_lock);
|
||||||
|
|
||||||
|
Adc *dev = _dev(line);
|
||||||
|
|
||||||
|
if (_adc_configure(dev, res) != 0) {
|
||||||
|
DEBUG("adc: configuration failed\n");
|
||||||
|
mutex_unlock(&_lock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int val = _sample(line) << _shift_from_res(res);
|
||||||
|
|
||||||
|
_adc_poweroff(dev);
|
||||||
|
mutex_unlock(&_lock);
|
||||||
|
|
||||||
|
return val;
|
||||||
}
|
}
|
||||||
|
@ -128,6 +128,33 @@ int adc_init(adc_t line);
|
|||||||
*/
|
*/
|
||||||
int32_t adc_sample(adc_t line, adc_res_t res);
|
int32_t adc_sample(adc_t line, adc_res_t res);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configure the ADC with a given resolution for continuous sampling
|
||||||
|
*
|
||||||
|
* @note requires the `periph_adc_continuous` feature
|
||||||
|
*
|
||||||
|
* @param[in] res resolution to use for conversion
|
||||||
|
*/
|
||||||
|
void adc_continuous_begin(adc_res_t res);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sample an ADC line without powering off the ADC afterward
|
||||||
|
*
|
||||||
|
* @note requires the `periph_adc_continuous` feature
|
||||||
|
*
|
||||||
|
* @brief Sample a value from the given ADC line
|
||||||
|
*
|
||||||
|
* @return the sampled value on success
|
||||||
|
*/
|
||||||
|
int32_t adc_continuous_sample(adc_t line);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disable the ADC to save power
|
||||||
|
*
|
||||||
|
* @note requires the `periph_adc_continuous` feature
|
||||||
|
*/
|
||||||
|
void adc_continuous_stop(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -188,6 +188,11 @@ config HAS_PERIPH_ADC
|
|||||||
help
|
help
|
||||||
Indicates that an ADC peripheral is present.
|
Indicates that an ADC peripheral is present.
|
||||||
|
|
||||||
|
config HAS_PERIPH_ADC_CONTINUOUS
|
||||||
|
bool
|
||||||
|
help
|
||||||
|
Indicates that an ADC peripheral can be left on between measurements.
|
||||||
|
|
||||||
config HAS_PERIPH_CAN
|
config HAS_PERIPH_CAN
|
||||||
bool
|
bool
|
||||||
help
|
help
|
||||||
|
9
tests/periph/adc_continuous/Makefile
Normal file
9
tests/periph/adc_continuous/Makefile
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
BOARD ?= same54-xpro
|
||||||
|
include ../Makefile.periph_common
|
||||||
|
|
||||||
|
FEATURES_REQUIRED += periph_adc
|
||||||
|
FEATURES_REQUIRED += periph_adc_continuous
|
||||||
|
USEMODULE += ztimer
|
||||||
|
USEMODULE += ztimer_msec
|
||||||
|
|
||||||
|
include $(RIOTBASE)/Makefile.include
|
3
tests/periph/adc_continuous/Makefile.ci
Normal file
3
tests/periph/adc_continuous/Makefile.ci
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
BOARD_INSUFFICIENT_MEMORY := \
|
||||||
|
atmega8 \
|
||||||
|
#
|
13
tests/periph/adc_continuous/README.md
Normal file
13
tests/periph/adc_continuous/README.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
Expected result
|
||||||
|
===============
|
||||||
|
When running this test, you should see the samples of all configured ADC lines
|
||||||
|
continuously streamed to std-out.
|
||||||
|
|
||||||
|
Background
|
||||||
|
==========
|
||||||
|
This test application will initialize each configured ADC lines to sample with
|
||||||
|
10-bit accuracy. Once configured the application will continuously convert each
|
||||||
|
available channel and print the conversion results to std-out.
|
||||||
|
|
||||||
|
For verification of the output connect the ADC pins to known voltage levels
|
||||||
|
and compare the output.
|
58
tests/periph/adc_continuous/main.c
Normal file
58
tests/periph/adc_continuous/main.c
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014-2015 Freie Universität Berlin
|
||||||
|
*
|
||||||
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
|
* General Public License v2.1. See the file LICENSE in the top level
|
||||||
|
* directory for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup tests
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief Test application for peripheral ADC drivers
|
||||||
|
*
|
||||||
|
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||||
|
*
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "ztimer.h"
|
||||||
|
#include "periph/adc.h"
|
||||||
|
|
||||||
|
#define RES ADC_RES_10BIT
|
||||||
|
#define DELAY_MS 100U
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
int sample = 0;
|
||||||
|
|
||||||
|
puts("\nRIOT ADC peripheral driver test\n");
|
||||||
|
puts("This test will sample all available ADC lines once every 100ms with\n"
|
||||||
|
"a 10-bit resolution and print the sampled results to STDIO\n\n");
|
||||||
|
|
||||||
|
/* initialize all available ADC lines */
|
||||||
|
for (unsigned i = 0; i < ADC_NUMOF; i++) {
|
||||||
|
if (adc_init(ADC_LINE(i)) < 0) {
|
||||||
|
printf("Initialization of ADC_LINE(%u) failed\n", i);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
printf("Successfully initialized ADC_LINE(%u)\n", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
adc_continuous_begin(RES);
|
||||||
|
while (1) {
|
||||||
|
for (unsigned i = 0; i < ADC_NUMOF; i++) {
|
||||||
|
sample = adc_continuous_sample(ADC_LINE(i));
|
||||||
|
printf("ADC_LINE(%u): %i\n", i, sample);
|
||||||
|
}
|
||||||
|
ztimer_sleep(ZTIMER_MSEC, DELAY_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
adc_continuous_stop();
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user