Skip to content

Instantly share code, notes, and snippets.

@Palatis
Created December 30, 2016 01:16
Show Gist options
  • Save Palatis/4af649cb9e1a13158794f141b150c65b to your computer and use it in GitHub Desktop.
Save Palatis/4af649cb9e1a13158794f141b150c65b to your computer and use it in GitHub Desktop.
#ifndef __ADCMUX_HPP__
#define __ADCMUX_HPP__
#include <Arduino.h>
#include <cstdarg>
extern "C" int system_adc_read();
#ifndef ADC_RESOLUTION_BITS
#define ADC_RESOLUTION_BITS (10) // hardware ADC resolution
#endif
template <
int8_t PIN1 = NOT_A_PIN, int8_t PIN2 = NOT_A_PIN, int8_t PIN3 = NOT_A_PIN, int8_t PIN4 = NOT_A_PIN,
int8_t PIN5 = NOT_A_PIN, int8_t PIN6 = NOT_A_PIN, int8_t PIN7 = NOT_A_PIN, int8_t PIN8 = NOT_A_PIN
> class ADCMux {
public:
void init() {
_initPin<PIN1, PIN1>()();
_initPin<PIN2, PIN2>()();
_initPin<PIN3, PIN3>()();
_initPin<PIN4, PIN4>()();
_initPin<PIN5, PIN5>()();
_initPin<PIN6, PIN6>()();
_initPin<PIN7, PIN7>()();
_initPin<PIN8, PIN8>()();
}
int analogRead(uint8_t channel, uint8_t oversample_bits = ADC_RESOLUTION_BITS) {
_selectPin<PIN1, 0x01 << 0>()(channel);
_selectPin<PIN2, 0x01 << 1>()(channel);
_selectPin<PIN3, 0x01 << 2>()(channel);
_selectPin<PIN4, 0x01 << 3>()(channel);
_selectPin<PIN5, 0x01 << 4>()(channel);
_selectPin<PIN6, 0x01 << 5>()(channel);
_selectPin<PIN7, 0x01 << 6>()(channel);
_selectPin<PIN8, 0x01 << 7>()(channel);
size_t loop = 0;
if (oversample_bits > ADC_RESOLUTION_BITS)
loop = oversample_bits - ADC_RESOLUTION_BITS;
loop = 0x01 << loop;
// clear out the SAR ADC capacitor by reading it once
system_adc_read();
int result = 0;
noInterrupts();
for (int i = 0;i < loop;++i)
result += system_adc_read();
interrupts();
return result;
}
private:
template <int8_t PIN, uint32_t MASK>
class _selectPin {
public:
void operator()(uint8_t channel) {
#ifdef DEBUG_ADCMUX
Serial.printf("_selectPin(): PIN = %d, MASK = 0x%08x, channel = %d\n", PIN, MASK, channel);
#endif
digitalWrite(PIN, channel & MASK ? HIGH : LOW);
}
};
// dunno why I can't specialize with `template <>`, so this UNUSED is here.
template <int8_t PIN, int8_t UNUSED>
class _initPin {
public:
void operator()() {
#ifdef DEBUG_ADCMUX
Serial.printf("_initPin(): pinMode(%d, OUTPUT);\n", PIN);
#endif
pinMode(PIN, OUTPUT);
}
};
};
template <int8_t PIN1, int8_t PIN2, int8_t PIN3, int8_t PIN4, int8_t PIN5, int8_t PIN6, int8_t PIN7, int8_t PIN8>
template <uint32_t MASK>
class ADCMux<PIN1, PIN2, PIN3, PIN4, PIN5, PIN6, PIN7, PIN8>::_selectPin<NOT_A_PIN, MASK> {
public:
void operator()(uint8_t channel) {}
};
template <int8_t PIN1, int8_t PIN2, int8_t PIN3, int8_t PIN4, int8_t PIN5, int8_t PIN6, int8_t PIN7, int8_t PIN8>
template <int8_t UNUSED>
class ADCMux<PIN1, PIN2, PIN3, PIN4, PIN5, PIN6, PIN7, PIN8>::_initPin<NOT_A_PIN, UNUSED> {
public:
void operator()() {}
};
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment