Skip to content
Snippets Groups Projects
Commit 57f60819 authored by Joakim Nohlgård's avatar Joakim Nohlgård
Browse files

sys/analog_util: Refactor adc_map, fix compilation

Change the API to use int32_t instead of int, to allow for greater
flexibility on 8- and 16-bit platforms. Removed limitation on input
arguments that min < max. Times where it can be useful to have min > max
is when measuring a sensor where a higher measured voltage means a lower
physical value. For example a thermistor can be connected so that the
measured voltage goes down when the temperature goes up.
parent 11b668fd
No related branches found
No related tags found
No related merge requests found
/*
* Copyright (C) 2018 Eistec AB
* Copyright (C) 2015 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
......@@ -14,28 +15,58 @@
* @brief ADC utility function implementation
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
*
* @}
*/
#include <stdint.h>
#include <inttypes.h>
#include "cpu.h"
#include "periph/adc.h"
#include "analog_util.h"
#include "assert.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
/* keep a max value to ADC resolution mapping for quick access in the ROM */
static const int val_max[] = {
[ADC_RES_6BIT] = 0x003f,
[ADC_RES_8BIT] = 0x00ff,
[ADC_RES_10BIT] = 0x03ff,
[ADC_RES_12BIT] = 0x0fff,
[ADC_RES_14BIT] = 0x3fff,
[ADC_RES_16BIT] = 0xffff
};
/**
* @brief Convert adc_res_t resolution setting into numeric bit count
*/
static unsigned int _adc_res_bits(adc_res_t res)
{
switch (res) {
case ADC_RES_6BIT:
return 6;
case ADC_RES_8BIT:
return 8;
case ADC_RES_10BIT:
return 10;
case ADC_RES_12BIT:
return 12;
case ADC_RES_14BIT:
return 14;
case ADC_RES_16BIT:
return 16;
default:
/* Unsupported ADC resolution, modify your application to use a
* different resolution, or add it above */
assert(0 == 1);
return 0;
}
}
int adc_util_map(int sample, adc_res_t res, int min, int max)
int32_t adc_util_map(int sample, adc_res_t res, int32_t min, int32_t max)
{
return ((((max - min) * sample) / val_max[res]) + min);
/* Using 64 bit signed int as intermediate to prevent overflow when range
* multiplied by sample requires more than 32 bits */
int32_t scaled = (((int64_t)(max - min) * sample) >> _adc_res_bits(res));
DEBUG("scaled: %" PRId32 "\n", scaled);
return (min + scaled);
}
float adc_util_mapf(int sample, adc_res_t res, float min, float max)
{
return ((((max - min) * sample) / val_max[res]) + min);
return ((((max - min) * sample) / ((int32_t)1L << _adc_res_bits(res))) + min);
}
......@@ -22,6 +22,7 @@
#define ANALOG_UTIL_H
#include <stdint.h>
#include "periph/adc.h"
#ifdef __cplusplus
......@@ -34,8 +35,6 @@ extern "C" {
* This function is useful for converting sampled ADC values into their physical
* representation.
*
* The min value is asserted to be smaller than the max value.
*
* @param[in] sample sampled ADC value
* @param[in] res ADC resolution
* @param[in] min the lower bound of the target interval
......@@ -43,7 +42,7 @@ extern "C" {
*
* @return the mapped value
*/
int adc_util_map(int sample, adc_res_t res, int min, int max);
int32_t adc_util_map(int sample, adc_res_t res, int32_t min, int32_t max);
/**
* @brief Map a sampled ADC value to a given range (using floating point
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment