#pragma once #include #include "../io/io.hpp" namespace adc { namespace detail { #if defined(__AVR_ATmega328P__) /* The following works in avr-gcc 5.4.0, but is not legal C++, because ptr's are not legal constexpr's: constexpr auto *foo = ptr; Workaround is to store the address of the ptr in a uintptr_t and reinterpret_cast it at call site. The _SFR_ADDR macro in sfr_defs.h would give the address, but it does that by taking the address of the dereferenced pointer and casts it to uint16_t, which is still not a legal constexpr. The workaround therefore is to disable the pointer-cast-and-dereference macro _MMIO_BYTE temporarily. */ #pragma push_macro("_MMIO_BYTE") #undef _MMIO_BYTE #define _MMIO_BYTE struct Registers { static constexpr uintptr_t MUX_SEL_ADDR = ADMUX; static constexpr uintptr_t CTRL_STAT_A_ADDR = ADCSRA; static constexpr uintptr_t DATA_L_ADDR = ADCL; static constexpr uintptr_t DATA_H_ADDR = ADCH; static constexpr uintptr_t CTRL_STAT_B_ADDR = ADCSRB; static constexpr uintptr_t DIG_IN_DIS_ADDR = DIDR0; }; enum class ControlFlagsMUX { CHANNEL_SEL_0 = MUX0, CHANNEL_SEL_1 = MUX1, CHANNEL_SEL_2 = MUX2, CHANNEL_SEL_3 = MUX3, LEFT_ADJ_RES = ADLAR, REF_SEL_0 = REFS0, REF_SEL_1 = REFS1, }; enum class ControlFlagsA { PRESCALER_SEL_0 = ADPS0, PRESCALER_SEL_1 = ADPS1, PRESCALER_SEL_2 = ADPS2, CONV_COMPLETE_INT_ENABLE = ADIE, CONV_COMPLETE = ADIF, AUTO_TRIGGER = ADATE, START_CONV = ADSC, ENABLE = ADEN, }; enum class ControlFlagsB { TRIGGER_SRC_0 = ADTS0, TRIGGER_SRC_1 = ADTS1, TRIGGER_SRC_2 = ADTS2, ANALOG_COMP_MUX_ENABLE = ACME, }; enum class ControlFlagsDigInDis { DIGITAL_INPUT_DISABLE_0 = ADC0D, DIGITAL_INPUT_DISABLE_1 = ADC1D, DIGITAL_INPUT_DISABLE_2 = ADC2D, DIGITAL_INPUT_DISABLE_3 = ADC3D, DIGITAL_INPUT_DISABLE_4 = ADC4D, DIGITAL_INPUT_DISABLE_5 = ADC5D, }; // clang-format off constexpr int operator<<(const int &lhs, const ControlFlagsMUX &rhs) { return lhs << static_cast(rhs); } constexpr int operator<<(const int &lhs, const ControlFlagsA &rhs) { return lhs << static_cast(rhs); } constexpr int operator<<(const int &lhs, const ControlFlagsB &rhs) { return lhs << static_cast(rhs); } // clang-format on template struct supports_adc { static constexpr auto value = (io::detail::getBus(pin) == io::Bus::C) ? true : false; }; template constexpr auto supports_adc_v = supports_adc::value; #pragma pop_macro("_MMIO_BYTE") #else #error "This chip is not supported" #endif } // namespace detail } // namespace adc