Skip to content

Commit c0ca636

Browse files
JordanYatesfabiobaltieri
authored andcommitted
adc: add microvolt conversion functions
Add a family of functions that convert to microvolts instead of millivolts. The resolution of an ADC with a 600 mV reference and a 12 bit output (nRF SAADC for example) is an order of magnitude better than millivolts (0.146 mV), even before considering non-unity gains. Signed-off-by: Jordan Yates <[email protected]>
1 parent 8ab300d commit c0ca636

File tree

1 file changed

+82
-17
lines changed
  • include/zephyr/drivers

1 file changed

+82
-17
lines changed

include/zephyr/drivers/adc.h

Lines changed: 82 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -859,10 +859,10 @@ static inline uint16_t adc_ref_internal(const struct device *dev)
859859
}
860860

861861
/**
862-
* @brief Convert a raw ADC value to millivolts.
862+
* @brief Conversion from raw ADC units to a specific output unit
863863
*
864864
* This function performs the necessary conversion to transform a raw
865-
* ADC measurement to a voltage in millivolts.
865+
* ADC measurement to a physical voltage.
866866
*
867867
* @param ref_mv the reference voltage used for the measurement, in
868868
* millivolts. This may be from adc_ref_internal() or a known
@@ -875,15 +875,21 @@ static inline uint16_t adc_ref_internal(const struct device *dev)
875875
* resolution in struct adc_sequence.
876876
*
877877
* @param valp pointer to the raw measurement value on input, and the
878-
* corresponding millivolt value on successful conversion. If
878+
* corresponding output value on successful conversion. If
879879
* conversion fails the stored value is left unchanged.
880880
*
881881
* @retval 0 on successful conversion
882882
* @retval -EINVAL if the gain is not reversible
883883
*/
884-
static inline int adc_raw_to_millivolts(int32_t ref_mv,
885-
enum adc_gain gain,
886-
uint8_t resolution,
884+
typedef int (*adc_raw_to_x_fn)(int32_t ref_mv, enum adc_gain gain, uint8_t resolution,
885+
int32_t *valp);
886+
887+
/**
888+
* @brief Convert a raw ADC value to millivolts.
889+
*
890+
* @see adc_raw_to_x_fn
891+
*/
892+
static inline int adc_raw_to_millivolts(int32_t ref_mv, enum adc_gain gain, uint8_t resolution,
887893
int32_t *valp)
888894
{
889895
int32_t adc_mv = *valp * ref_mv;
@@ -897,20 +903,43 @@ static inline int adc_raw_to_millivolts(int32_t ref_mv,
897903
}
898904

899905
/**
900-
* @brief Convert a raw ADC value to millivolts using information stored
901-
* in a struct adc_dt_spec.
906+
* @brief Convert a raw ADC value to microvolts.
907+
*
908+
* @see adc_raw_to_x_fn
909+
*/
910+
static inline int adc_raw_to_microvolts(int32_t ref_mv, enum adc_gain gain, uint8_t resolution,
911+
int32_t *valp)
912+
{
913+
int64_t adc_uv = (int64_t)*valp * ref_mv * 1000;
914+
int ret = adc_gain_invert_64(gain, &adc_uv);
915+
916+
if (ret == 0) {
917+
*valp = (int32_t)(adc_uv >> resolution);
918+
}
919+
920+
return ret;
921+
}
922+
923+
/**
924+
* @brief Convert a raw ADC value to an arbitrary output unit
902925
*
926+
* @param[in] conv_func Function that converts to the final output unit.
903927
* @param[in] spec ADC specification from Devicetree.
928+
* @param[in] channel_cfg Channel configuration used for sampling. This can be
929+
* either the configuration from @a spec, or an alternate sampling configuration
930+
* based on @a spec, for example a different gain value.
904931
* @param[in,out] valp Pointer to the raw measurement value on input, and the
905-
* corresponding millivolt value on successful conversion. If conversion fails
932+
* corresponding output value on successful conversion. If conversion fails
906933
* the stored value is left unchanged.
907934
*
908-
* @return A value from adc_raw_to_millivolts() or -ENOTSUP if information from
935+
* @return A value from adc_raw_to_x_fn or -ENOTSUP if information from
909936
* Devicetree is not valid.
910-
* @see adc_raw_to_millivolts()
937+
* @see adc_raw_to_x_fn
911938
*/
912-
static inline int adc_raw_to_millivolts_dt(const struct adc_dt_spec *spec,
913-
int32_t *valp)
939+
static inline int adc_raw_to_x_dt_chan(adc_raw_to_x_fn conv_func,
940+
const struct adc_dt_spec *spec,
941+
const struct adc_channel_cfg *channel_cfg,
942+
int32_t *valp)
914943
{
915944
int32_t vref_mv;
916945
uint8_t resolution;
@@ -919,7 +948,7 @@ static inline int adc_raw_to_millivolts_dt(const struct adc_dt_spec *spec,
919948
return -ENOTSUP;
920949
}
921950

922-
if (spec->channel_cfg.reference == ADC_REF_INTERNAL) {
951+
if (channel_cfg->reference == ADC_REF_INTERNAL) {
923952
vref_mv = (int32_t)adc_ref_internal(spec->dev);
924953
} else {
925954
vref_mv = spec->vref_mv;
@@ -931,12 +960,48 @@ static inline int adc_raw_to_millivolts_dt(const struct adc_dt_spec *spec,
931960
* For differential channels, one bit less needs to be specified
932961
* for resolution to achieve correct conversion.
933962
*/
934-
if (spec->channel_cfg.differential) {
963+
if (channel_cfg->differential) {
935964
resolution -= 1U;
936965
}
937966

938-
return adc_raw_to_millivolts(vref_mv, spec->channel_cfg.gain,
939-
resolution, valp);
967+
return conv_func(vref_mv, channel_cfg->gain, resolution, valp);
968+
}
969+
970+
971+
/**
972+
* @brief Convert a raw ADC value to millivolts using information stored
973+
* in a struct adc_dt_spec.
974+
*
975+
* @param[in] spec ADC specification from Devicetree.
976+
* @param[in,out] valp Pointer to the raw measurement value on input, and the
977+
* corresponding millivolt value on successful conversion. If conversion fails
978+
* the stored value is left unchanged.
979+
*
980+
* @return A value from adc_raw_to_millivolts() or -ENOTSUP if information from
981+
* Devicetree is not valid.
982+
* @see adc_raw_to_millivolts()
983+
*/
984+
static inline int adc_raw_to_millivolts_dt(const struct adc_dt_spec *spec, int32_t *valp)
985+
{
986+
return adc_raw_to_x_dt_chan(adc_raw_to_millivolts, spec, &spec->channel_cfg, valp);
987+
}
988+
989+
/**
990+
* @brief Convert a raw ADC value to microvolts using information stored
991+
* in a struct adc_dt_spec.
992+
*
993+
* @param[in] spec ADC specification from Devicetree.
994+
* @param[in,out] valp Pointer to the raw measurement value on input, and the
995+
* corresponding microvolt value on successful conversion. If conversion fails
996+
* the stored value is left unchanged.
997+
*
998+
* @return A value from adc_raw_to_microvolts() or -ENOTSUP if information from
999+
* Devicetree is not valid.
1000+
* @see adc_raw_to_microvolts()
1001+
*/
1002+
static inline int adc_raw_to_microvolts_dt(const struct adc_dt_spec *spec, int32_t *valp)
1003+
{
1004+
return adc_raw_to_x_dt_chan(adc_raw_to_microvolts, spec, &spec->channel_cfg, valp);
9401005
}
9411006

9421007
/**

0 commit comments

Comments
 (0)