#ifndef ADC_HPP #define ADC_HPP #include "config.hpp" #include "hardware.hpp" #include #include "../io/io.hpp" namespace adc { namespace detail { extern void (*fnAdcIntHandler)(const uint16_t &); using reg_ptr_t = volatile uint8_t *; template static inline reg_ptr_t getRegPtr() { return reinterpret_cast(Address); } template class AdcImpl { public: static uint16_t read() { *getRegPtr() |= 1 << ControlFlagsA::START_CONV; while (*getRegPtr() & (1 << ControlFlagsA::START_CONV)) ; uint16_t adcSample = *getRegPtr(); adcSample |= *getRegPtr() << 8; return adcSample; } protected: static void init(uint8_t muxVal) { *getRegPtr() = muxVal | calcRef(); auto ctrlStatA = calcCtrlStatA(detail::fnAdcIntHandler != nullptr); *getRegPtr() = ctrlStatA; constexpr auto ctrlStatB = calcCtrlStatB(); *getRegPtr() = ctrlStatB; if constexpr (Cfg::MODE == Mode::FREE_RUNNING) { *getRegPtr() |= 1 << ControlFlagsA::START_CONV; } } static constexpr auto calcRef() { uint8_t muxVal = 0; if constexpr (Cfg::VREF == VoltageRef::AVCC) { muxVal |= 1 << ControlFlagsMUX::REF_SEL_0; } else if constexpr (Cfg::VREF == VoltageRef::INTERNAL) { muxVal |= (1 << ControlFlagsMUX::REF_SEL_0) | (1 << ControlFlagsMUX::REF_SEL_1); } return muxVal; } static constexpr uint8_t calcPrescaler() { constexpr auto validPrescaler = Cfg::PRESCALER == 2 || Cfg::PRESCALER == 4 || Cfg::PRESCALER == 8 || Cfg::PRESCALER == 16 || Cfg::PRESCALER == 32 || Cfg::PRESCALER == 64 || Cfg::PRESCALER == 128; static_assert(validPrescaler, "Invalid prescaler"); // clang-format off switch (Cfg::PRESCALER) { case 2: return 1; case 4: return 2; case 8: return 3; case 16: return 4; case 32: return 5; case 64: return 6; case 128: return 7; } // clang-format on } static auto calcCtrlStatA(bool interruptEnable) { uint8_t ctrlStatA = 1 << ControlFlagsA::ENABLE; if constexpr (Cfg::MODE == Mode::AUTO || Cfg::MODE == Mode::FREE_RUNNING) { ctrlStatA |= 1 << ControlFlagsA::AUTO_TRIGGER; } if (interruptEnable) { ctrlStatA |= 1 << ControlFlagsA::CONV_COMPLETE_INT_ENABLE; } return ctrlStatA | calcPrescaler(); } static constexpr uint8_t calcCtrlStatB() { if constexpr (Cfg::MODE == Mode::AUTO) { // clang-format off switch (Cfg::TRIGGER_SRC) { case TriggerSource::FREE_RUNNING: return 0; case TriggerSource::ANALOG_COMP: return 1; case TriggerSource::EXTERNAL_INT_0: return 2; case TriggerSource::TIMER0_COMP_A: return 3; case TriggerSource::TIMER0_OVERFLOW: return 4; case TriggerSource::TIMER1_COMP_B: return 5; case TriggerSource::TIMER1_OVERFLOW: return 6; case TriggerSource::TIMER1_CAPTURE: return 7; } // clang-format on } return 0; } }; } // namespace detail template class Adc { public: static_assert(sizeof(Input) == -1, "Invalid input source selected"); }; template class Adc : public detail::AdcImpl { using callback_t = void (*)(const uint16_t &); public: static_assert(detail::supports_adc_v, "Pin does not support ADC"); static void init(callback_t callback) { detail::fnAdcIntHandler = callback; init(); } static void init() { constexpr auto muxVal = calcChannel(); detail::AdcImpl::init(muxVal); } private: static constexpr auto calcChannel() { return static_cast(pin) - static_cast(io::P::C0); } }; template class Adc : public detail::AdcImpl { using callback_t = void (*)(uint16_t); public: static void init(callback_t callback) { detail::fnAdcIntHandler = callback; init(); } static void init() { constexpr auto muxVal = calcChannel(); detail::AdcImpl::init(muxVal); } private: static constexpr auto calcChannel() { using mx = detail::ControlFlagsMUX; // clang-format off switch (src) { case InputSource::TEMP: return 1 << mx::CHANNEL_SEL_3; case InputSource::VBG: return (1 << mx::CHANNEL_SEL_3) | (1 << mx::CHANNEL_SEL_2) | (1 << mx::CHANNEL_SEL_1); case InputSource::GND: return (1 << mx::CHANNEL_SEL_3) | (1 << mx::CHANNEL_SEL_2) | (1 << mx::CHANNEL_SEL_1) | (1 << mx::CHANNEL_SEL_0); } // clang-format on } }; } // namespace adc #endif ////////////////////////////////////////////////////////////////////////// #ifdef ADC_INT_VECTOR #include #include namespace adc { namespace detail { #if defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega328P__) void (*fnAdcIntHandler)(const uint16_t &) = nullptr; ISR(ADC_vect) { if (fnAdcIntHandler) { const auto adcSample = *getRegPtr() | (*getRegPtr() << 8); fnAdcIntHandler(adcSample); } } #else #error "This chip is not supported" #endif } // namespace detail } // namespace adc #undef ADC_INT_VECTORS #endif