diff --git a/src/shared/drivers/adc/InternalADC.cpp b/src/shared/drivers/adc/InternalADC.cpp index 91909daed229999a66f81523cd99ce3c06d81f1b..bf628feb6feb48c1c3f729f4797cde0316403d0e 100644 --- a/src/shared/drivers/adc/InternalADC.cpp +++ b/src/shared/drivers/adc/InternalADC.cpp @@ -25,20 +25,20 @@ #include <drivers/timer/TimestampTimer.h> #include <utils/ClockUtils.h> -#define ADC_RESOLUTION 4095 +static constexpr int ADC_RESOLUTION = 4095; #if defined(STM32F407xx) || defined(STM32F429xx) -#define TEMP30_CAL_VALUE ((uint16_t*)((uint32_t)0x1FFF7A2C)) -#define TEMP110_CAL_VALUE ((uint16_t*)((uint32_t)0x1FFF7A2E)) -#define TEMP30 30 -#define TEMP110 110 -#define CALIBRATION_V_DDA 3.3f +#define CAL_PT1_VALUE ((uint16_t *)((uint32_t)0x1FFF7A2C)) +#define CAL_PT2_VALUE ((uint16_t *)((uint32_t)0x1FFF7A2E)) +static constexpr float CAL_PT1_TEMP = 30; +static constexpr float CAL_PT2_TEMP = 110; +static constexpr float CAL_V_DDA = 3.3f; #elif defined(STM32F767xx) || defined(STM32F769xx) -#define TEMP30_CAL_VALUE ((uint16_t*)((uint32_t)0x1FF0F44C)) -#define TEMP110_CAL_VALUE ((uint16_t*)((uint32_t)0x1FF0F44E)) -#define TEMP30 30 -#define TEMP110 110 -#define CALIBRATION_V_DDA 3.3f +#define CAL_PT1_VALUE ((uint16_t *)((uint32_t)0x1FF0F44C)) +#define CAL_PT2_VALUE ((uint16_t *)((uint32_t)0x1FF0F44E)) +static constexpr float CAL_PT1_TEMP = 30; +static constexpr float CAL_PT2_TEMP = 110; +static constexpr float CAL_V_DDA = 3.3f; #else #warning This micro controller does not have a calibrated temperature sensor or is not currently supported by this driver #define WITHOUT_CALIBRATION @@ -47,12 +47,11 @@ #if defined(STM32F407xx) || defined(STM32F205xx) #define TEMP_CH InternalADC::CH16 #define VBAT_CH InternalADC::CH18 -#define VBAT_DIV 2.0f +static constexpr float VBAT_DIV = 2.0f; #elif defined(STM32F429xx) || defined(STM32F767xx) || defined(STM32F769xx) #define TEMP_CH InternalADC::CH18 #define VBAT_CH InternalADC::CH18 -#define SINGLE_AUX_CHANNEL -#define VBAT_DIV 4.0f +static constexpr float VBAT_DIV = 4.0f; #endif // Error the user if the current target is missing the V_DDA_VOLTAGE macro @@ -62,23 +61,36 @@ #error Missing V_DDA_VOLTAGE definition for current target #endif -#ifndef WITHOUT_CALIBRATION -namespace InternalADCConsts -{ // Factory calibration values // Read "Temperature sensor characteristics" chapter in the datasheet -static const float voltage30 = - static_cast<float>(*TEMP30_CAL_VALUE) * CALIBRATION_V_DDA / ADC_RESOLUTION; -static const float voltage110 = - static_cast<float>(*TEMP110_CAL_VALUE) * CALIBRATION_V_DDA / ADC_RESOLUTION; -static const float slope = (voltage110 - voltage30) / (TEMP110 - TEMP30); -} // namespace InternalADCConsts +#ifndef WITHOUT_CALIBRATION + +float getCalPt1Voltage() +{ + static float pt1Voltage = + static_cast<float>(*CAL_PT1_VALUE) * CAL_V_DDA / ADC_RESOLUTION; + return pt1Voltage; +} + +float getCalPt2Voltage() +{ + static float pt2Voltage = + static_cast<float>(*CAL_PT2_VALUE) * CAL_V_DDA / ADC_RESOLUTION; + return pt2Voltage; +} + +float getCalSlope() +{ + static float slope = (getCalPt2Voltage() - getCalPt1Voltage()) / + (CAL_PT2_TEMP - CAL_PT1_TEMP); + return slope; +} #endif namespace Boardcore { -InternalADC::InternalADC(ADC_TypeDef* adc) : adc(adc) +InternalADC::InternalADC(ADC_TypeDef *adc) : adc(adc) { resetRegisters(); ClockUtils::enablePeripheralClock(adc); @@ -94,8 +106,7 @@ InternalADC::InternalADC(ADC_TypeDef* adc) : adc(adc) for (int i = 0; i < CH_NUM; i++) { - channelsEnabled[i] = false; - channelsRawValues[i] = 0; + channelsEnabled[i] = false; } } @@ -117,41 +128,69 @@ bool InternalADC::selfTest() { return true; } InternalADCData InternalADC::sampleImpl() { + InternalADCData newData; + newData.timestamp = TimestampTimer::getTimestamp(); + for (int i = 0; i < CH16; i++) { if (channelsEnabled[i]) { - channelsRawValues[i] = readChannel(static_cast<Channel>(i)); + newData.voltage[i] = readChannel(static_cast<Channel>(i)); + newData.voltage[i] = + newData.voltage[i] * V_DDA_VOLTAGE / ADC_RESOLUTION; } } /** - * The temperature and vbat sensors are enabled and then disabled. If left - * enabled they somehow disrupt other channels measurements. I did not find - * description of this behaviour anywhere but observed it during testing. - * - * Also the temperature sensors has a startup time of 10us. 12us is used - * because during test 10us were not enough. + * Quirk: the temperature and vbat sensors are enabled and then disabled. If + * left enabled they somehow disrupt other channels measurements. I did not + * find description of this behaviour anywhere but observed it during + * testing. Also the temperature sensors has a startup time of 10us. 12us is + * used because during test 10us were not enough. + * The startup time is the same for all Boardcore supported micros. */ if (tempEnabled) { ADC->CCR |= ADC_CCR_TSVREFE; - miosix::delayUs(12); - temperatureRawValue = readChannel(static_cast<Channel>(TEMP_CH)); + miosix::delayUs(12); // Temperature sensor startup time + auto temperatureRawValue = readChannel(static_cast<Channel>(TEMP_CH)); ADC->CCR &= ~ADC_CCR_TSVREFE; + + // Conversion + if (temperatureRawValue != 0) + { + newData.temperature = + temperatureRawValue * V_DDA_VOLTAGE / ADC_RESOLUTION; + +#ifdef WITHOUT_CALIBRATION + // Default conversion + newData.temperature = ((newData.temperature - 0.76) / 0.0025) + 25; +#else + // Factory calibration + newData.temperature = newData.temperature - getCalPt1Voltage(); + newData.temperature /= getCalSlope(); + newData.temperature += CAL_PT1_TEMP; +#endif + } + else + { + newData.temperature = 0; + } } if (vbatEnabled) { ADC->CCR |= ADC_CCR_VBATE; - vbatVoltageRawValue = readChannel(static_cast<Channel>(VBAT_CH)); + auto vbatVoltageRawValue = readChannel(static_cast<Channel>(VBAT_CH)); ADC->CCR &= ~ADC_CCR_VBATE; - } - timestamp = TimestampTimer::getTimestamp(); + // Conversion + newData.vBat = + vbatVoltageRawValue * V_DDA_VOLTAGE / ADC_RESOLUTION * VBAT_DIV; + } - return lastSample; + return newData; } void InternalADC::enableChannel(Channel channel, SampleTime sampleTime) @@ -163,8 +202,7 @@ void InternalADC::enableChannel(Channel channel, SampleTime sampleTime) void InternalADC::disableChannel(Channel channel) { - channelsEnabled[channel] = false; - channelsRawValues[channel] = 0; + channelsEnabled[channel] = false; } void InternalADC::enableTemperature(SampleTime sampleTime) @@ -193,50 +231,30 @@ void InternalADC::disableVbat() disableChannel(VBAT_CH); } -InternalADCData InternalADC::getVoltage(Channel channel) +ADCData InternalADC::getVoltage(Channel channel) { - return {timestamp, channel, - channelsRawValues[channel] * - V_DDA_VOLTAGE / // cppcheck-suppress ConfigurationNotChecked - ADC_RESOLUTION}; + ADCData data; + data.voltageTimestamp = getLastSample().timestamp; + data.voltage = getLastSample().voltage[channel]; + data.channelId = channel; + return data; } TemperatureData InternalADC::getTemperature() { TemperatureData data; - data.temperatureTimestamp = timestamp; - - if (temperatureRawValue != 0) - { - data.temperature = - temperatureRawValue * - V_DDA_VOLTAGE / // cppcheck-suppress ConfigurationNotChecked - ADC_RESOLUTION; - -#ifdef WITHOUT_CALIBRATION - // Default conversion - data.temperature = ((data.temperature - 0.76) / 0.0025) + 25; -#else - // Factory calibration - data.temperature = ((data.temperature - InternalADCConsts::voltage30) / - InternalADCConsts::slope) + - TEMP30; -#endif - } - else - { - data.temperature = 0; - } - + data.temperatureTimestamp = getLastSample().temperature; + data.temperature = getLastSample().temperature; return data; } -InternalADCData InternalADC::getVbatVoltage() +ADCData InternalADC::getVbatVoltage() { - return {timestamp, VBAT_CH, - vbatVoltageRawValue * - V_DDA_VOLTAGE / // cppcheck-suppress ConfigurationNotChecked - ADC_RESOLUTION * VBAT_DIV}; + ADCData data; + data.voltageTimestamp = getLastSample().timestamp; + data.voltage = getLastSample().vBat; + data.channelId = VBAT_CH; + return data; } inline void InternalADC::resetRegisters() diff --git a/src/shared/drivers/adc/InternalADC.h b/src/shared/drivers/adc/InternalADC.h index 5746a54fb61ed359c1cea43a98c017d153de820a..ac094ec820fe7f369019cec23278bdca04ab893d 100644 --- a/src/shared/drivers/adc/InternalADC.h +++ b/src/shared/drivers/adc/InternalADC.h @@ -122,11 +122,11 @@ public: void disableVbat(); - InternalADCData getVoltage(Channel channel); + ADCData getVoltage(Channel channel); TemperatureData getTemperature(); - InternalADCData getVbatVoltage(); + ADCData getVbatVoltage(); private: void resetRegisters(); @@ -140,11 +140,6 @@ private: bool channelsEnabled[CH_NUM]; bool tempEnabled = false; bool vbatEnabled = false; - - uint16_t channelsRawValues[CH_NUM]; - uint16_t temperatureRawValue = 0; - uint16_t vbatVoltageRawValue = 0; - uint64_t timestamp = 0; }; } // namespace Boardcore diff --git a/src/shared/drivers/adc/InternalADCData.h b/src/shared/drivers/adc/InternalADCData.h index f43612ae1514166af2e0d25a6bc92813afcbe9a4..b751fab43a2c5248e4f539a854e073042b58676d 100644 --- a/src/shared/drivers/adc/InternalADCData.h +++ b/src/shared/drivers/adc/InternalADCData.h @@ -27,24 +27,33 @@ namespace Boardcore { -struct InternalADCData : public ADCData +struct InternalADCData { - InternalADCData() : ADCData{0, 0, 0.0} {} + uint64_t timestamp = 0; + float voltage[16]; + float temperature; + float vBat; - InternalADCData(uint64_t t, uint8_t channelId, float voltage) - : ADCData{t, channelId, voltage} - { - } + InternalADCData() {} static std::string header() { - return "voltageTimestamp,channelId,voltage\n"; + return "timestamp,,voltage_0,voltage_1,voltage_2,voltage_3,voltage_4," + "voltage_5,voltage_6,voltage_7,voltage_8,voltage_9,voltage_10," + "voltage_11,voltage_12,voltage_13,voltage_14,voltage_15," + "temperature,vBat,voltage\n"; } void print(std::ostream& os) const { - os << voltageTimestamp << "," << (int)channelId << "," << voltage - << "\n"; + os << timestamp << ","; + + for (int i = 0; i < 16; i++) + { + os << voltage[i] << ","; + } + + os << temperature << "," << vBat << "\n"; } };