rusefi/firmware/hw_layer/adc/adc_inputs.h

118 lines
3.3 KiB
C

/**
* @file adc_inputs.h
* @brief Low level internal ADC code
*
* @date Jan 14, 2013
* @author Andrey Belomutskiy, (c) 2012-2020
*/
#pragma once
#include "global.h"
#include "adc_math.h"
#ifndef SLOW_ADC_RATE
#define SLOW_ADC_RATE 500
#endif
float getAnalogInputDividerCoefficient(adc_channel_e);
inline bool isAdcChannelValid(adc_channel_e hwChannel) {
/* Compiler will optimize, keep following if as a reminder */
if (hwChannel >= EFI_ADC_TOTAL_CHANNELS) {
/* this should not happen!
* if we have enum out of range somewhere in settings
* that means something goes terribly wrong
* TODO: should we say something?
*/
return false;
}
return ((hwChannel > EFI_ADC_NONE) && (hwChannel < EFI_ADC_TOTAL_CHANNELS));
}
inline bool isAdcChannelOnChip(adc_channel_e hwChannel) {
return (isAdcChannelValid(hwChannel) && (hwChannel <= EFI_ADC_ONCHIP_LAST));
}
inline bool isAdcChannelOffChip(adc_channel_e hwChannel) {
return (isAdcChannelValid(hwChannel) && (hwChannel > EFI_ADC_ONCHIP_LAST));
}
#if !defined(GPT_FREQ_FAST) || !defined(GPT_PERIOD_FAST)
/*
* 8000 RPM is 133Hz
* If we want to sample MAP once per 5 degrees we need 133Hz * (360 / 5) = 9576Hz of fast ADC ~= 10 KHz
*/
/*
* TODO: migrate to continuous ADC mode? probably not - we cannot afford the callback in continuous mode.
* TODO: look into other options
* TODO: ADC convertion can be triggered directly from timer, with no SW intervention
*/
/* PWM clock frequency. Timer clock = 100 KHz */
#define GPT_FREQ_FAST 100000
/* PWM period (in PWM ticks), 100 KHz / 10 = 10KHz callback rate */
#define GPT_PERIOD_FAST 10
/*
* We have 1 / (GPT_FREQ_FAST / GPT_PERIOD_FAST) to finish conversion = 100 uS
* With ADC_SAMPLING_FAST = 28 ADC clock @ 21 MHz (F4) -> one channel conversion takes 1.33(3) uS
* Oversampling is ADC_BUF_DEPTH_FAST = 4
* We can do up-to 100 / (1.33(3) * 4) = 18.75 channels conversions
* So we can enable ALL channels for fast ADC.
* This will increase bus load with more DMA transfers, but who cares?
*/
#endif /* GPT_FREQ_FAST GPT_PERIOD_FAST */
#if HAL_USE_ADC
enum class AdcChannelMode : char {
Off,
Slow,
Fast
};
AdcChannelMode getAdcMode(adc_channel_e hwChannel);
void initAdcInputs();
// wait until at least 1 slowADC sampling is complete
void waitForSlowAdc(uint32_t lastAdcCounter = 1);
void printFullAdcReportIfNeeded(void);
int getInternalAdcValue(const char *msg, adc_channel_e index);
float getMCUInternalTemperature(void);
void addFastAdcChannel(const char *name, adc_channel_e hwChannel);
void removeChannel(const char *name, adc_channel_e hwChannel);
#define getAdcValue(msg, hwChannel) getInternalAdcValue(msg, hwChannel)
#define adcToVoltsDivided(adc, hwChannel) (adcToVolts(adc) * getAnalogInputDividerCoefficient(hwChannel))
// This callback is called by the ADC driver when a new fast ADC sample is ready
void onFastAdcComplete(adcsample_t* samples);
using AdcToken = uint32_t;
using AdcTockenInternal = union {
AdcToken token;
struct {
uint16_t adc;
uint16_t channel;
} __attribute__((packed));
};
static_assert(sizeof(AdcTockenInternal) == sizeof(AdcToken));
static constexpr AdcToken invalidAdcToken = (AdcToken)(-1);
AdcToken enableFastAdcChannel(const char* msg, adc_channel_e channel);
adcsample_t getFastAdc(AdcToken token);
#endif // HAL_USE_ADC
void printFullAdcReport(void);