adc/hardware.hpp

96 lines
2.5 KiB
C++

#pragma once
#include <stdint.h>
#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<int>(rhs); }
constexpr int operator<<(const int &lhs, const ControlFlagsA &rhs) { return lhs << static_cast<int>(rhs); }
constexpr int operator<<(const int &lhs, const ControlFlagsB &rhs) { return lhs << static_cast<int>(rhs); }
// clang-format on
template <io::P pin>
struct supports_adc {
static constexpr auto value = (io::detail::getBus(pin) == io::Bus::C) ? true : false;
};
template <io::P pin>
constexpr auto supports_adc_v = supports_adc<pin>::value;
#pragma pop_macro("_MMIO_BYTE")
#else
#error "This chip is not supported"
#endif
} // namespace detail
} // namespace adc