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/frdm-k64f/Makefile.dep
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
ifneq (,$(filter saul_default,$(USEMODULE)))
USEMODULE += saul_adc
USEMODULE += analog_util
endif

include $(RIOTCPU)/kinetis/Makefile.dep
13 changes: 12 additions & 1 deletion boards/frdm-k64f/include/adc_params.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,18 @@ static const saul_adc_params_t saul_adc_params[] =
{ .name = "ADC1_DP1", .line = ADC_LINE(15), .res = ADC_RES_16BIT, },
{ .name = "ADC1_DM1", .line = ADC_LINE(16), .res = ADC_RES_16BIT, },
{ .name = "ADC1_DP1-ADC1_DM1", .line = ADC_LINE(17), .res = ADC_RES_16BIT, },
{ .name = "coretemp", .line = ADC_LINE(18), .res = ADC_RES_16BIT, },
{
.name = "coretemp", .line = ADC_LINE(18), .res = ADC_RES_16BIT,
.unit = UNIT_TEMP_C, .scale = -1,
/* Scaling the temperature sensor voltage to units of 0.1 Celsius, this
* depends on several numbers found in the data sheet as well as the
* analog reference voltage (VREFH), which is 3.3 V on FRDM-K64F.
* These numbers yield a full range of -1570..466 Cel, which is
* unrealistic, but because of the physical limits, the sensor will ever
* only use a small range of that interval. */
.val_min = (int32_t)(250 - (( 0 - 716) / 1.62) * 10),
.val_max = (int32_t)(250 - ((3300 - 716) / 1.62) * 10),
},
{ .name = "corebandgap", .line = ADC_LINE(19), .res = ADC_RES_16BIT, },
};

Expand Down
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 += analog_util
endif

include $(RIOTCPU)/kinetis/Makefile.dep
19 changes: 16 additions & 3 deletions boards/mulle/include/adc_params.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,16 @@ extern "C" {
static const saul_adc_params_t saul_adc_params[] =
{
{
.name = "k60temp",
.line = ADC_LINE(0),
.res = ADC_RES_16BIT,
.name = "coretemp", .line = ADC_LINE(0), .res = ADC_RES_16BIT,
.unit = UNIT_TEMP_C, .scale = -1,
/* Scaling the temperature sensor voltage to units of 0.1 Celsius, this
* depends on several numbers found in the data sheet as well as the
* analog reference voltage (VREFH), which is 3.3 V on FRDM-K64F.
* These numbers yield a full range of -1570..466 Cel, which is
* unrealistic, but because of the physical limits, the sensor will ever
* only use a small range of that interval. */
.val_min = (int32_t)(250 - (( 0 - 716) / 1.62) * 10),
.val_max = (int32_t)(250 - ((3300 - 716) / 1.62) * 10),
},
{
.name = "k60vrefsh",
Expand Down Expand Up @@ -65,11 +72,17 @@ static const saul_adc_params_t saul_adc_params[] =
.name = "Vbat",
.line = MULLE_VBAT_ADC_LINE,
.res = ADC_RES_16BIT,
.unit = UNIT_V, .scale = -3,
.val_min = 0,
.val_max = (3300 * 2), /* Compensate for the ADC input connected to Vbat/2 */
},
{
.name = "Vchr",
.line = MULLE_VCHR_ADC_LINE,
.res = ADC_RES_16BIT,
.unit = UNIT_V, .scale = -3,
.val_min = 0,
.val_max = (3300 * 2), /* Compensate for the ADC input connected to Vchr/2 */
},
{
.name = "PGA0_DP",
Expand Down
4 changes: 4 additions & 0 deletions drivers/include/saul/periph.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ typedef struct {
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 */
int32_t val_min; /**< value corresponding to an ADC raw value of 0 */
int32_t val_max; /**< value corresponding to the maximum ADC reading */
uint8_t unit; /**< phydat unit */
int8_t scale; /**< phydat scale */
} saul_adc_params_t;
#endif /* MODULE_SAUL_ADC */

Expand Down
35 changes: 33 additions & 2 deletions drivers/saul/adc_saul.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,14 @@
#include "saul/periph.h"
#include "phydat.h"
#include "periph/adc.h"
#if MODULE_ANALOG_UTIL
#include "analog_util.h"
#endif


/* Unscaled version of sampling driver */
static int read_adc(const void *dev, phydat_t *res)
{
const saul_adc_params_t *params = *((const saul_adc_params_t **)dev);
const saul_adc_params_t *params = (const saul_adc_params_t *)dev;
res->val[0] = adc_sample(params->line, params->res);
memset(&(res->val[1]), 0, 2 * sizeof(res->val[1]));
/* Raw ADC reading has no unit */
Expand All @@ -42,3 +45,31 @@ const saul_driver_t adc_saul_driver = {
.write = saul_notsup,
.type = SAUL_SENSE_ANALOG,
};

/* Scaling version of sampling driver */
#if MODULE_ANALOG_UTIL
static int read_adc_scaled(const void *dev, phydat_t *res)
{
const saul_adc_params_t *params = (const saul_adc_params_t *)dev;
int raw = adc_sample(params->line, params->res);
int32_t value = adc_util_map(raw, params->res, params->val_min, params->val_max);
res->val[0] = value;
memset(&(res->val[1]), 0, 2 * sizeof(res->val[1]));
res->unit = params->unit;
res->scale = params->scale;
return 1;
}

/**
* @brief SAUL driver template
*/
#define ADC_SAUL_DRIVER_INSTANCE(saul_type, name) \
const saul_driver_t adc_saul_ ## name ## _driver = { \
.read = read_adc_scaled, \
.write = saul_notsup, \
.type = saul_type, \
}

ADC_SAUL_DRIVER_INSTANCE(SAUL_SENSE_TEMP, temp);
ADC_SAUL_DRIVER_INSTANCE(SAUL_SENSE_ANALOG, analog);
#endif
45 changes: 34 additions & 11 deletions sys/auto_init/saul/auto_init_adc.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,35 +32,58 @@
*/
#define SAUL_ADC_NUMOF (sizeof(saul_adc_params)/sizeof(saul_adc_params[0]))

/**
* @brief Allocate memory for pointers to the ADC parameter structs
*
* We use this extra level of indirection to be able to keep the saul_adc_params
* array const and residing in ROM.
*/
static const saul_adc_params_t *saul_adcs[SAUL_ADC_NUMOF];

/**
* @brief Memory for the registry entries
*/
static saul_reg_t saul_reg_entries[SAUL_ADC_NUMOF];

/**
* @brief Reference the driver struct
* @name driver struct references
* @{
*/
extern saul_driver_t adc_saul_driver;
#if MODULE_ANALOG_UTIL
extern saul_driver_t adc_saul_temp_driver;
extern saul_driver_t adc_saul_analog_driver;
#endif /* MODULE_ANALOG_UTIL */
/** @} */

void auto_init_adc(void)
{
for (unsigned i = 0; i < SAUL_ADC_NUMOF; i++) {
const saul_adc_params_t *p = &saul_adc_params[i];
saul_adcs[i] = p;

LOG_DEBUG("[auto_init_saul] initializing direct ADC #%u\n", i);

saul_reg_entries[i].dev = &saul_adcs[i];
/* discarding const qualifier of target type, the driver must only use
* it as if it is const though. */
saul_reg_entries[i].dev = (void *)p;
saul_reg_entries[i].name = p->name;
#if MODULE_ANALOG_UTIL
if (p->val_min != p->val_max) {
/* Apply scaling */
switch (p->unit) {
/* Pick the correct sensor type based on the unit */
case UNIT_TEMP_C:
case UNIT_TEMP_F:
case UNIT_TEMP_K:
saul_reg_entries[i].driver = &adc_saul_temp_driver;
break;
case UNIT_A:
case UNIT_V:
default:
/* Fall back: use sensor type SAUL_SENSE_ANALOG */
saul_reg_entries[i].driver = &adc_saul_analog_driver;
break;
}
}
else {
/* Unscaled raw values */
saul_reg_entries[i].driver = &adc_saul_driver;
}
#else /* MODULE_ANALOG_UTIL */
saul_reg_entries[i].driver = &adc_saul_driver;
#endif /* MODULE_ANALOG_UTIL */
/* initialize the ADC line */
adc_init(p->line);
/* add to registry */
Expand Down