Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions boards/mulle/Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ USEMODULE += periph_rtt
ifneq (,$(filter saul_default,$(USEMODULE)))
USEMODULE += saul_gpio
USEMODULE += saul_adc
USEMODULE += saul_adc_conversion
endif

include $(RIOTCPU)/kinetis/Makefile.dep
37 changes: 37 additions & 0 deletions boards/mulle/include/adc_params.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,41 @@

#include "board.h"
#include "saul/periph.h"
#if MODULE_SAUL_ADC_CONVERSION
#include "periph/adc_conv.h"
#endif

#ifdef __cplusplus
extern "C" {
#endif

#if MODULE_SAUL_ADC_CONVERSION
#define ADC_CONV(func) .conv = (func)
#else
#define ADC_CONV(ignore)
#endif

#if MODULE_SAUL_ADC_CONVERSION
/**
* @brief Convert Mulle Vbat, Vchr samples into real voltage
*
* @param[in] params SAUL ADC params pointer
* @param[in] res ADC sample
*
* @return 1
*/
static int mulle_vbat_volts(const saul_adc_params_t *params, phydat_t *res)
{
adc_conv_saul_adc_volts(params, res);
/* The Vbat, Vchr measurement point is located on a voltage divider which
* shows half of the full voltage, to be able to measure voltages greater
* than ADC Vref. */
phydat_fit(res, res->val[0] * 2, 0, 0);

return 1;
}
#endif

/**
* @brief ADC configuration
*/
Expand All @@ -40,36 +70,43 @@ static const saul_adc_params_t saul_adc_params[] =
.name = "k60vrefsh",
.line = ADC_LINE(2),
.res = ADC_RES_16BIT,
ADC_CONV(adc_conv_saul_adc_volts),
},
{
.name = "k60vrefsl",
.line = ADC_LINE(3),
.res = ADC_RES_16BIT,
ADC_CONV(adc_conv_saul_adc_volts),
},
{
.name = "k60bandgap",
.line = ADC_LINE(1),
.res = ADC_RES_16BIT,
ADC_CONV(adc_conv_saul_adc_volts),
},
{
.name = "DAC0feedback",
.line = ADC_LINE(4),
.res = ADC_RES_16BIT,
ADC_CONV(adc_conv_saul_adc_volts),
},
{
.name = "VREFfeedback",
.line = ADC_LINE(5),
.res = ADC_RES_16BIT,
ADC_CONV(adc_conv_saul_adc_volts),
},
{
.name = "Vbat",
.line = MULLE_VBAT_ADC_LINE,
.res = ADC_RES_16BIT,
ADC_CONV(mulle_vbat_volts),
},
{
.name = "Vchr",
.line = MULLE_VCHR_ADC_LINE,
.res = ADC_RES_16BIT,
ADC_CONV(mulle_vbat_volts),
},
{
.name = "PGA0_DP",
Expand Down
9 changes: 9 additions & 0 deletions boards/mulle/include/board.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@
#include "mulle-nvram.h"
#include "mtd.h"

/**
* @name ADC sample conversion configuration
* @{
*/
#define BOARD_ADC_VREFH_DEFAULT (33000)
#define BOARD_ADC_VREFL_DEFAULT ( 0)
#define BOARD_ADC_VREF_SCALE_DEFAULT (-4)
/** @} */

/* Use the on board RTC 32kHz clock for LPTMR clocking. */
#undef LPTIMER_CLKSRC
/** @brief Clock source for the LPTMR module */
Expand Down
4 changes: 4 additions & 0 deletions drivers/Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,10 @@ ifneq (,$(filter pcd8544,$(USEMODULE)))
USEMODULE += xtimer
endif

ifneq (,$(filter periph_common,$(USEMODULE)))
USEMODULE += analog_util
endif

ifneq (,$(filter pir,$(USEMODULE)))
FEATURES_REQUIRED += periph_gpio
USEMODULE += xtimer
Expand Down
101 changes: 101 additions & 0 deletions drivers/include/periph/adc_conv.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright (C) 2018 Eistec AB
*
* 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 drivers_periph_adc
* @{
*
* @file
* @brief Conversion routines for CPU ADC samples
*
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
*
* @}
*/

#include "periph/adc.h"
#if MODULE_SAUL_ADC
#include "saul/periph.h"
#endif

#ifndef BOARD_ADC_VREFH_DEFAULT
/**
* @brief Boot default for vrefh
*/
/* 3300 mV is as good as any other guess */
#define BOARD_ADC_VREFH_DEFAULT (3300)
#endif

#ifndef BOARD_ADC_VREFL_DEFAULT
/**
* @brief Boot default for vrefl
*/
/* 0 mV is as good as any other guess */
#define BOARD_ADC_VREFL_DEFAULT (0)
#endif

#ifndef BOARD_ADC_VREF_SCALE_DEFAULT
/**
* @brief Boot default for vref scale
*/
/* millivolts by default */
#define BOARD_ADC_VREF_SCALE_DEFAULT (-3)
#endif

/**
* @brief Convert ADC sample to actual voltage
*
* This function uses the stored ADC reference voltage for the conversion
*
* @param[in] sample an ADC reading
* @param[in] res ADC resolution setting
*/
int adc_conv_volts(int sample, adc_res_t res);

/**
* @brief Update the internal upper voltage reference value
*
* This should be called if the software knows that the reference voltage for
* the ADC has changed since last update.
*
* @param[in] new_vrefh new reference voltage
*/
void adc_conv_set_vrefh(int new_vrefh);

/**
* @brief Update the internal lower voltage reference value
*
* This should be called if the software knows that the reference voltage for
* the ADC has changed since last update.
*
* @param[in] new_vrefl new reference voltage
*/
void adc_conv_set_vrefl(int new_vrefl);

/**
* @brief Set the ADC VREF unit scale exponent
*
* This is the 10 exponent for the value in vrefh/vrefl, i.e.
* Real Vrefh = vrefh * 10^(scale)
* For example, scale = -3 means that vrefh, vrefl are given in millivolts.
*
* @param[in] new_scale Vref unit scale exponent
*/
void adc_conv_set_scale(int new_scale);

#if MODULE_SAUL_ADC || DOXYGEN
/**
* @brief SAUL ADC compatible conversion wrapper function
*
* @param[in] params SAUL ADC params pointer
* @param[in] res ADC sample
*
* @return 1
*/
int adc_conv_saul_adc_volts(const saul_adc_params_t *params, phydat_t *res);
#endif
17 changes: 16 additions & 1 deletion drivers/include/saul/periph.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,28 @@ typedef struct {
#endif /* MODULE_SAUL_GPIO */

#if MODULE_SAUL_ADC || DOXYGEN
#if MODULE_SAUL_ADC_CONVERSION || DOXYGEN
/* Forward declaration */
struct saul_adc_params;

/**
* @brief ADC result conversion function pointer type
*
* @param[in] params pointer to ADC params
* @param[in] res an ADC sample
*/
typedef int (*adc_conv_t)(const struct saul_adc_params *params, phydat_t *res);
#endif
/**
* @brief Direct mapped ADC configuration values
*/
typedef struct {
typedef struct saul_adc_params {
const char *name; /**< name of the device connected to this pin */
adc_t line; /**< ADC line to initialize and expose */
adc_res_t res; /**< ADC resolution */
#if MODULE_SAUL_ADC_CONVERSION || DOXYGEN
adc_conv_t conv; /**< ADC result conversion function, NULL for no-op */
#endif
} saul_adc_params_t;
#endif /* MODULE_SAUL_ADC */

Expand Down
94 changes: 94 additions & 0 deletions drivers/periph_common/adc_conv.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Copyright (C) 2018 Eistec AB
*
* 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 drivers_periph_adc
* @{
*
* @file
* @brief Implementations of conversion routines for CPU internal analog signals
*
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
*
* @}
*/

#include <stdint.h>

#include "board.h"
#include "phydat.h"
#include "periph/adc.h"
#include "periph/adc_conv.h"
#include "analog_util.h"

#define ENABLE_DEBUG 0
#include "debug.h"

/**
* @brief ADC low side potential
*
* An ADC reading of zero means that the sampled voltage is close to or less than this value.
*/
static int vrefl = BOARD_ADC_VREFL_DEFAULT;

/**
* @brief ADC reference voltage high potential
*
* An ADC reading of max means that the sampled voltage is close to or greater than this value
*/
static int vrefh = BOARD_ADC_VREFH_DEFAULT;

/**
* @brief ADC unit scale exponent
*
* e.g. -3 for millivolts
*/
static int vref_scale = BOARD_ADC_VREF_SCALE_DEFAULT;

int adc_conv_volts(int sample, adc_res_t res)
{
/* Convert to voltage */
/* sample is in the range 0..max, where 0 means the sampled voltage was in
* the range [vrefl, vrefl + LSB), and max means the sampled voltage was in
* the range [vrefh - LSB, vrefh) */
return adc_util_map(sample, res, vrefl, vrefh);
}

void adc_conv_set_vrefh(int new_vrefh)
{
vrefh = new_vrefh;
}

void adc_conv_set_vrefl(int new_vrefl)
{
vrefl = new_vrefl;
}

void adc_conv_set_scale(int new_scale)
{
vref_scale = new_scale;
}

#if MODULE_SAUL_ADC
int adc_conv_saul_adc_volts(const saul_adc_params_t *params, phydat_t *res)
{
int sample = res->val[0];
if (params->res == ADC_RES_16BIT) {
/* Assume single-ended reading for now, clear sign bits */
sample &= 0xffff;
}
int converted = adc_conv_volts(sample, params->res);
DEBUG("vref: %de%d\n", vrefh, vref_scale);
DEBUG("conv: %d\n", converted);
res->unit = UNIT_V;
res->scale = vref_scale;
phydat_fit(res, converted, 0, 0);
DEBUG("res: %d\n", res->val[0]);
return 1;
}
#endif
5 changes: 5 additions & 0 deletions drivers/saul/adc_saul.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ static int read_adc(const void *dev, phydat_t *res)
/* Raw ADC reading has no unit */
res->unit = UNIT_NONE;
res->scale = 0;
#if MODULE_SAUL_ADC_CONVERSION
if (params->conv) {
return params->conv(params, res);
}
#endif
return 1;
}

Expand Down
1 change: 1 addition & 0 deletions makefiles/pseudomodules.inc.mk
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ PSEUDOMODULES += prng
PSEUDOMODULES += prng_%
PSEUDOMODULES += rdcli_simple_standalone
PSEUDOMODULES += saul_adc
PSEUDOMODULES += saul_adc_conversion
PSEUDOMODULES += saul_default
PSEUDOMODULES += saul_gpio
PSEUDOMODULES += schedstatistics
Expand Down