1 // Copyright 2021 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 #pragma once 15 #include "pw_analog/analog_input.h" 16 #include "pw_chrono/system_clock.h" 17 #include "pw_result/result.h" 18 #include "pw_status/try.h" 19 20 namespace pw::analog { 21 22 // The common interface for obtaining voltage samples in microvolts. This 23 // interface represents a single voltage input or channel. Users will need to 24 // supply their own ADC driver implementation in order to configure and enable 25 // the ADC peripheral in order to provide the reference voltages and to 26 // configure and enable the ADC peripheral where needed. Users are responsible 27 // for managing multithreaded access to the ADC driver if the ADC services 28 // multiple channels. 29 class MicrovoltInput : public AnalogInput { 30 public: 31 // Specifies the max and min microvolt range the analog input can measure. 32 // The reference voltage difference cannot be bigger than sizeof(int32_t) 33 // which should be just above 2000V. 34 // * These values do not change at run time. 35 // * Inversion of min/max is supported. 36 struct References { 37 int32_t max_voltage_uv; // Microvolts at AnalogInput::Limits::max 38 int32_t min_voltage_uv; // Microvolts at AnalogInput::Limits::min. 39 }; 40 41 virtual ~MicrovoltInput() = default; 42 43 // Blocks until the specified timeout duration has elapsed or the voltage 44 // sample has been returned, whichever comes first. 45 // 46 // This method is thread safe. 47 // 48 // Returns: 49 // Microvolts (uV). 50 // ResourceExhuasted: ADC peripheral in use. 51 // DeadlineExceedded: Timed out waiting for a sample. 52 // Other statuses left up to the implementer. TryReadMicrovoltsFor(chrono::SystemClock::duration timeout)53 Result<int32_t> TryReadMicrovoltsFor(chrono::SystemClock::duration timeout) { 54 return TryReadMicrovoltsUntil( 55 chrono::SystemClock::TimePointAfterAtLeast(timeout)); 56 } 57 58 // Blocks until the deadline time has been reached or the voltage sample has 59 // been returned, whichever comes first. 60 // 61 // This method is thread safe. 62 // 63 // Returns: 64 // Microvolts (uV). 65 // ResourceExhuasted: ADC peripheral in use. 66 // DeadlineExceedded: Timed out waiting for a sample. 67 // Other statuses left up to the implementer. TryReadMicrovoltsUntil(chrono::SystemClock::time_point deadline)68 Result<int32_t> TryReadMicrovoltsUntil( 69 chrono::SystemClock::time_point deadline) { 70 PW_TRY_ASSIGN(const int32_t sample, TryReadUntil(deadline)); 71 72 const References reference = GetReferences(); 73 const AnalogInput::Limits limits = GetLimits(); 74 75 constexpr int64_t kMaxReferenceDiffUv = std::numeric_limits<int32_t>::max(); 76 77 if (std::abs(static_cast<int64_t>(reference.max_voltage_uv) - 78 static_cast<int64_t>(reference.min_voltage_uv)) > 79 kMaxReferenceDiffUv) { 80 return pw::Status::Internal(); 81 } 82 83 return (((static_cast<int64_t>(sample) - static_cast<int64_t>(limits.min)) * 84 (reference.max_voltage_uv - reference.min_voltage_uv)) / 85 (limits.max - limits.min)) + 86 reference.min_voltage_uv; 87 } 88 89 private: 90 // Returns the reference voltage needed to calculate the voltage. 91 // These values do not change at run time. 92 virtual References GetReferences() const = 0; 93 }; 94 95 } // namespace pw::analog 96