You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

89 lines
2.4KB

  1. // Copyright 2011 Olivier Gillet.
  2. //
  3. // Author: Olivier Gillet (ol.gillet@gmail.com)
  4. //
  5. // This program is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. #ifndef AVRLIBX_IO_ADC_H_
  16. #define AVRLIBX_IO_ADC_H_
  17. #include <avr/io.h>
  18. #include "avrlibx/avrlibx.h"
  19. #include "avrlibx/io/gpio.h"
  20. namespace avrlibx {
  21. template<typename Port, uint8_t channel>
  22. struct ADCChannelWrapper { };
  23. #define WRAP_ADC_CHANNEL(port, index) \
  24. template<> \
  25. struct ADCChannelWrapper<Port ## port, index> { \
  26. static inline ADC_t& adc() { return ADC ## port; } \
  27. static inline ADC_CH_t& channel() { return ADC ## port.CH ## index; } \
  28. };
  29. WRAP_ADC_CHANNEL(A, 0)
  30. WRAP_ADC_CHANNEL(A, 1)
  31. WRAP_ADC_CHANNEL(A, 2)
  32. WRAP_ADC_CHANNEL(A, 3)
  33. #ifdef ADCB
  34. WRAP_ADC_CHANNEL(B, 0)
  35. WRAP_ADC_CHANNEL(B, 1)
  36. WRAP_ADC_CHANNEL(B, 2)
  37. WRAP_ADC_CHANNEL(B, 3)
  38. #endif
  39. template<
  40. typename Port,
  41. uint8_t channel,
  42. uint8_t prescaler = 7>
  43. struct ADC {
  44. typedef ADCChannelWrapper<Port, channel> adc;
  45. static inline void Init() {
  46. adc::adc().CTRLA |= ADC_ENABLE_bm;
  47. adc::adc().CTRLB = ADC_CONMODE_bm | 0x06; // Signed mode + left aligned.
  48. adc::adc().REFCTRL = ADC_REFSEL1_bm; // External reference on port A.
  49. adc::adc().PRESCALER = prescaler;
  50. adc::channel().CTRL = ADC_CH_INPUTMODE1_bm; // Differential input.
  51. }
  52. static inline void StartConversion(uint8_t pin) {
  53. adc::channel().MUXCTRL = (pin << ADC_CH_MUXPOS_gp) | 1;
  54. adc::channel().CTRL |= ADC_CH_START_bm;
  55. }
  56. static inline uint8_t readable() { return adc::channel().INTFLAGS; }
  57. static inline void Wait() {
  58. while (!readable());
  59. adc::channel().INTFLAGS = 1;
  60. }
  61. static inline int16_t Read() {
  62. Wait();
  63. return ReadOut();
  64. }
  65. static inline int16_t ReadOut() {
  66. return adc::channel().RES;
  67. }
  68. static inline int8_t ReadOut8() {
  69. return adc::channel().RESH;
  70. }
  71. };
  72. } // namespace avrlibx
  73. #endif // AVRLIBX_IO_ADC_H_