mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2024-11-30 08:20:21 +00:00
229 lines
8.7 KiB
C
229 lines
8.7 KiB
C
/**
|
|
* @file furi_hal_adc.h
|
|
* @brief ADC HAL API
|
|
*
|
|
* For the sake of simplicity this API implements only small subset
|
|
* of what ADC is actually capable of. Feel free to visit Reference
|
|
* Manual for STM32WB series and implement any other modes by your
|
|
* self.
|
|
*
|
|
* Couple things to keep in mind:
|
|
*
|
|
* - ADC resolution is 12 bits, but effective number of bits is ~10 at the best
|
|
* and further depends on how you use and configure it.
|
|
* - Analog domain is fed from SMPS which is quite noisy.
|
|
* - Because of that we use internal on-chip voltage reference for ADC.
|
|
* - It's capable of producing 2 voltages: 2.5V and 2.048V. This is the scale
|
|
* for your signal.
|
|
* - Only single ended mode is available. But you can implement differential one
|
|
* by using low level controls directly.
|
|
* - No DMA or interrupt API available at this point. But can be implemented
|
|
* with low level controls.
|
|
*
|
|
*
|
|
* How to use:
|
|
*
|
|
* - furi_hal_gpio_init - Configure your pins in `GpioModeAnalog`
|
|
* - furi_hal_adc_acquire - acquire ADC handle to work with
|
|
* - furi_hal_adc_configure - configure ADC block
|
|
* - furi_hal_adc_read - read value
|
|
* - furi_hal_adc_release - release ADC handle
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <furi.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
typedef struct FuriHalAdcHandle FuriHalAdcHandle;
|
|
|
|
typedef enum {
|
|
FuriHalAdcScale2048, /**< 2.048V scale */
|
|
FuriHalAdcScale2500, /**< 2.5V scale */
|
|
} FuriHalAdcScale;
|
|
|
|
typedef enum {
|
|
FuriHalAdcClockSync16, /**< 16MHZ, synchronous */
|
|
FuriHalAdcClockSync32, /**< 32MHZ, synchronous */
|
|
FuriHalAdcClockSync64, /**< 64MHz, synchronous */
|
|
} FuriHalAdcClock;
|
|
|
|
typedef enum {
|
|
FuriHalAdcOversample2, /**< ADC will take 2 samples per each value */
|
|
FuriHalAdcOversample4, /**< ADC will take 4 samples per each value */
|
|
FuriHalAdcOversample8, /**< ADC will take 8 samples per each value */
|
|
FuriHalAdcOversample16, /**< ADC will take 16 samples per each value */
|
|
FuriHalAdcOversample32, /**< ADC will take 32 samples per each value */
|
|
FuriHalAdcOversample64, /**< ADC will take 64 samples per each value */
|
|
FuriHalAdcOversample128, /**< ADC will take 128 samples per each value */
|
|
FuriHalAdcOversample256, /**< ADC will take 256 samples per each value */
|
|
FuriHalAdcOversampleNone, /**< disable oversampling */
|
|
} FuriHalAdcOversample;
|
|
|
|
typedef enum {
|
|
FuriHalAdcSamplingtime2_5, /**< Sampling time 2.5 ADC clock */
|
|
FuriHalAdcSamplingtime6_5, /**< Sampling time 6.5 ADC clock */
|
|
FuriHalAdcSamplingtime12_5, /**< Sampling time 12.5 ADC clock */
|
|
FuriHalAdcSamplingtime24_5, /**< Sampling time 24.5 ADC clock */
|
|
FuriHalAdcSamplingtime47_5, /**< Sampling time 47.5 ADC clock */
|
|
FuriHalAdcSamplingtime92_5, /**< Sampling time 92.5 ADC clock */
|
|
FuriHalAdcSamplingtime247_5, /**< Sampling time 247.5 ADC clock */
|
|
FuriHalAdcSamplingtime640_5, /**< Sampling time 640.5 ADC clock */
|
|
} FuriHalAdcSamplingTime;
|
|
|
|
typedef enum {
|
|
/* Channels 0 - 5 are fast channels */
|
|
FuriHalAdcChannel0, /**< Internal channel, see `FuriHalAdcChannelVREFINT`. */
|
|
FuriHalAdcChannel1, /**< Channel 1p */
|
|
FuriHalAdcChannel2, /**< Channel 2p or 1n */
|
|
FuriHalAdcChannel3, /**< Channel 3p or 2n */
|
|
FuriHalAdcChannel4, /**< Channel 4p or 3n */
|
|
FuriHalAdcChannel5, /**< Channel 5p or 4n */
|
|
/* Channels 6 - 18 are slow channels */
|
|
FuriHalAdcChannel6, /**< Channel 6p or 5n */
|
|
FuriHalAdcChannel7, /**< Channel 7p or 6n */
|
|
FuriHalAdcChannel8, /**< Channel 8p or 7n */
|
|
FuriHalAdcChannel9, /**< Channel 9p or 8n */
|
|
FuriHalAdcChannel10, /**< Channel 10p or 9n */
|
|
FuriHalAdcChannel11, /**< Channel 11p or 10n */
|
|
FuriHalAdcChannel12, /**< Channel 12p or 11n */
|
|
FuriHalAdcChannel13, /**< Channel 13p or 12n */
|
|
FuriHalAdcChannel14, /**< Channel 14p or 13n */
|
|
FuriHalAdcChannel15, /**< Channel 15p or 14n */
|
|
FuriHalAdcChannel16, /**< Channel 16p or 15n */
|
|
FuriHalAdcChannel17, /**< Internal channel, see `FuriHalAdcChannelTEMPSENSOR`. */
|
|
FuriHalAdcChannel18, /**< Internal channel, see `FuriHalAdcChannelVBAT`. */
|
|
/* Special Channels: combines one of the 0-18 channel and additional internal peripherals */
|
|
FuriHalAdcChannelVREFINT, /**< Special channel for VREFINT, used for calibration and self test */
|
|
FuriHalAdcChannelTEMPSENSOR, /**< Special channel for on-die temperature sensor, requires at least 5us of sampling time */
|
|
FuriHalAdcChannelVBAT, /**< Special channel for VBAT/3 voltage, requires at least 12us of sampling time */
|
|
/* Special value to indicate that pin is not connected to ADC */
|
|
FuriHalAdcChannelNone, /**< No channel */
|
|
} FuriHalAdcChannel;
|
|
|
|
/** Initialize ADC subsystem */
|
|
void furi_hal_adc_init(void);
|
|
|
|
/** Acquire ADC handle
|
|
*
|
|
* Enables appropriate power and clocking domains
|
|
*
|
|
* @return FuriHalAdcHandle pointer
|
|
*/
|
|
FuriHalAdcHandle* furi_hal_adc_acquire(void);
|
|
|
|
/** Release ADC handle
|
|
*
|
|
* @param handle The ADC handle
|
|
*/
|
|
void furi_hal_adc_release(FuriHalAdcHandle* handle);
|
|
|
|
/** Configure with default parameters and enable ADC
|
|
*
|
|
* Parameters used:
|
|
* - FuriHalAdcScale2048 - 2.048V VREF Scale. Your signal should be in 0 -
|
|
* 2.048V range.
|
|
* - FuriHalAdcClockSync64 - Clocked from sysclk bus at 64MHz in synchronous
|
|
* mode. Fast, no delay on data bus access.
|
|
* - FuriHalAdcOversample64 - Going to acquire and average 64 samples. For
|
|
* circuits with slowly or not changing signal. Total time per one read:
|
|
* (1/64)*(12.5+247.5)*64 = 260us. The best results you'll get if your signal
|
|
* will stay on the same level all this time.
|
|
* - FuriHalAdcSamplingtime247_5 - Sampling(transfer from source to internal
|
|
* sampling capacitor) time is 247.5 ADC clocks: (1/64)*247.5 = 3.8671875us.
|
|
* For relatively high impedance circuits.
|
|
*
|
|
* Also keep your measurement circuit impedance under 10KOhm or oversampling
|
|
* results will be compromised. Verify your signal with oscilloscope(you may
|
|
* need fast oscilloscope: 200MHz bandwidth, 125MS/s), ensure that signal is not
|
|
* distorted by sampling.
|
|
*
|
|
* Those parameters were optimized for 0 - 2.048 voltage measurement with ~0.1%
|
|
* precision. You can get more, but it will require some magic.
|
|
*
|
|
* @param handle The ADC handle
|
|
*/
|
|
void furi_hal_adc_configure(FuriHalAdcHandle* handle);
|
|
|
|
/** Configure with extended parameters and enable ADC
|
|
*
|
|
* General advice is to start with default parameters, figure out what exactly
|
|
* is not working for you and then tune it. Also in some cases changing
|
|
* circuit(adding caps, lowering impedance, adding opamp) may be better than changing
|
|
* parameters.
|
|
*
|
|
* @warning In general ADC is a world of magic: make sure that you understand
|
|
* how your circuit and ADC works. Then carefully read STM32WB
|
|
* series reference manual. Setting incorrect parameters leads to
|
|
* very poor results. Also internal channels require special
|
|
* settings.
|
|
*
|
|
* @param handle The ADC handle
|
|
* @param[in] scale The ADC voltage scale
|
|
* @param[in] clock The ADC clock
|
|
* @param[in] oversample The ADC oversample mode
|
|
* @param[in] sampling_time The ADC sampling time
|
|
*/
|
|
void furi_hal_adc_configure_ex(
|
|
FuriHalAdcHandle* handle,
|
|
FuriHalAdcScale scale,
|
|
FuriHalAdcClock clock,
|
|
FuriHalAdcOversample oversample,
|
|
FuriHalAdcSamplingTime sampling_time);
|
|
|
|
/** Read single ADC value
|
|
*
|
|
* @param handle The ADC handle
|
|
* @param[in] channel The channel to sample
|
|
*
|
|
* @return value, 12 bits
|
|
*/
|
|
uint16_t furi_hal_adc_read(FuriHalAdcHandle* handle, FuriHalAdcChannel channel);
|
|
|
|
/** Convert sampled value to voltage
|
|
*
|
|
* @param handle The ADC handle
|
|
* @param[in] value The value acquired with `furi_hal_adc_read`
|
|
*
|
|
* @return Voltage in mV
|
|
*/
|
|
float furi_hal_adc_convert_to_voltage(FuriHalAdcHandle* handle, uint16_t value);
|
|
|
|
/** Convert sampled VREFINT value to voltage
|
|
*
|
|
* @param handle The ADC handle
|
|
* @param[in] value The value acquired with `furi_hal_adc_read` for
|
|
* `FuriHalAdcChannelVREFINT` channel
|
|
*
|
|
* @return Voltage in mV
|
|
*/
|
|
float furi_hal_adc_convert_vref(FuriHalAdcHandle* handle, uint16_t value);
|
|
|
|
/** Convert sampled TEMPSENSOR value to temperature
|
|
*
|
|
* @param handle The ADC handle
|
|
* @param[in] value The value acquired with `furi_hal_adc_read` for
|
|
* `FuriHalAdcChannelTEMPSENSOR` channel
|
|
*
|
|
* @return temperature in degree C
|
|
*/
|
|
float furi_hal_adc_convert_temp(FuriHalAdcHandle* handle, uint16_t value);
|
|
|
|
/** Convert sampled VBAT value to voltage
|
|
*
|
|
* @param handle The ADC handle
|
|
* @param[in] value The value acquired with `furi_hal_adc_read` for
|
|
* `FuriHalAdcChannelVBAT` channel
|
|
*
|
|
* @return Voltage in mV
|
|
*/
|
|
float furi_hal_adc_convert_vbat(FuriHalAdcHandle* handle, uint16_t value);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|