|
- // Copyright 2009 Olivier Gillet.
- //
- // Author: Olivier Gillet (ol.gillet@gmail.com)
- //
- // This program is free software: you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- // You should have received a copy of the GNU General Public License
- // along with this program. If not, see <http://www.gnu.org/licenses/>.
- //
- // -----------------------------------------------------------------------------
- //
- // Interface to the onboard ADC converter, and analog multiplexer.
-
- #ifndef AVRLIB_ADC_H_
- #define AVRLIB_ADC_H_
-
- #include <avr/io.h>
-
- #include "avrlib/avrlib.h"
-
- namespace avrlib {
-
- enum AdcReference {
- ADC_EXTERNAL = 0,
- ADC_DEFAULT = 1,
- ADC_INTERNAL = 3
- };
-
- enum AdcAlignment {
- ADC_RIGHT_ALIGNED = 0,
- ADC_LEFT_ALIGNED = 1
- };
-
- IORegister(ADCSRA);
-
- typedef BitInRegister<ADCSRARegister, ADSC> AdcConvert;
- typedef BitInRegister<ADCSRARegister, ADEN> AdcEnabled;
-
- class Adc {
- public:
- Adc() { }
-
- static inline void Init() {
- set_prescaler(7); // 128 -> 156kHz ADC clock.
- Enable();
- }
- static inline void set_prescaler(uint8_t factor) {
- ADCSRA = (ADCSRA & ~0x07) | (factor & 0x07);
- }
- static inline void set_reference(AdcReference reference) {
- admux_value_ = (admux_value_ & 0x3f) | (reference << 6);
- }
- static inline void set_alignment(AdcAlignment alignment) {
- admux_value_ &= 0xc0;
- if (alignment == ADC_LEFT_ALIGNED) {
- admux_value_ |= 0x20;
- }
- }
- static inline void Enable() {
- AdcEnabled::set();
- }
- static inline void Disable() {
- AdcEnabled::clear();
- }
- static inline int16_t Read(uint8_t pin) {
- StartConversion(pin);
- Wait();
- return ReadOut();
- }
-
- static inline void StartConversion(uint8_t pin) {
- ADMUX = admux_value_ | (pin & 0x07);
- AdcConvert::set();
- }
- static inline void Wait() {
- while (AdcConvert::value());
- }
- static bool ready() {
- return !AdcConvert::value();
- }
- static inline int16_t ReadOut() {
- uint8_t low = ADCL;
- uint8_t high = ADCH;
- return (high << 8) | low;
- }
- // Only works when the ADC is left aligned
- static inline uint8_t ReadOut8() {
- return ADCH;
- }
-
- private:
- static uint8_t admux_value_;
-
- DISALLOW_COPY_AND_ASSIGN(Adc);
- };
-
- // Class that cycles through all the analog pins and read their value. Compared
- // to Adc::Read(), this class is wait-free as it doesn't block on the
- // ADSC bit value.
- class AdcInputScanner {
- public:
- enum {
- buffer_size = 0,
- data_size = 16,
- };
-
- AdcInputScanner() { }
-
- static void Init() {
- Adc::Init();
- current_pin_ = 0;
- Adc::StartConversion(0);
- }
-
- static inline void set_num_inputs(uint8_t num_inputs) {
- num_inputs_ = num_inputs;
- }
-
- static inline int16_t Read(uint8_t pin) {
- return state_[pin];
- }
-
- static inline uint8_t Read8(uint8_t pin) {
- return static_cast<uint16_t>(state_[pin]) >> 8;
- }
-
- static uint8_t current_pin() {
- return current_pin_;
- }
-
- static int16_t Sync(uint8_t pin) {
- Adc::Wait();
- int16_t value = Adc::Read(pin);
- Adc::StartConversion(current_pin_);
- return value;
- }
-
- static void Scan() {
- Adc::Wait();
- state_[current_pin_] = Adc::ReadOut();
- ++current_pin_;
- if (current_pin_ >= num_inputs_) {
- current_pin_ = 0;
- }
- Adc::StartConversion(current_pin_);
- }
-
- private:
- static uint8_t current_pin_;
- static uint8_t num_inputs_;
- static int16_t state_[8];
-
- DISALLOW_COPY_AND_ASSIGN(AdcInputScanner);
- };
-
- template<int pin>
- struct AnalogInput {
- enum {
- buffer_size = 0,
- data_size = 16,
- };
- static void Init() { }
- static int16_t Read() {
- return Adc::Read(pin);
- }
- };
-
- template<int id>
- class MuxedAnalogInput {
- public:
- enum {
- buffer_size = 0,
- data_size = 16,
- };
- static void Init() { }
- static int16_t Read() {
- return Adc::Read(current_pin_);
- }
- static void set_pin(uint8_t current_pin) {
- current_pin_ = current_pin;
- }
-
- private:
- static uint8_t current_pin_;
- };
-
- /* static */
- template<int id>
- uint8_t MuxedAnalogInput<id>::current_pin_ = 0;
-
- } // namespace avrlib
-
- #endif // AVRLIB_ADC_H_
|