adc.cpp 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. #include "adc.h"
  2. #include <stdio.h>
  3. #include <avr/io.h>
  4. #include <avr/interrupt.h>
  5. #include <avr/pgmspace.h>
  6. #include <string.h>
  7. #include "pins.h"
  8. static uint8_t adc_count; //used for oversampling
  9. static uint8_t adc_channel_idx; //bitmask index
  10. volatile uint8_t adc_channel; //regular index
  11. volatile uint16_t adc_values[ADC_CHAN_CNT];
  12. static void adc_reset();
  13. static void adc_setmux(uint8_t ch);
  14. void adc_init()
  15. {
  16. puts_P(PSTR("adc_init"));
  17. DIDR0 = ((ADC_CHAN_MSK & ADC_DIDR_MSK) & 0xff); //disable digital inputs PORTF
  18. DIDR2 = ((ADC_CHAN_MSK & ADC_DIDR_MSK) >> 8); //disable digital inputs PORTK
  19. ADMUX |= (1 << REFS0); //use AVCC as reference
  20. //enable ADC, set prescaler/128, enable interrupt
  21. ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0) | (1 << ADIF) | (1 << ADIE);
  22. }
  23. static void adc_reset()
  24. {
  25. static const uint8_t first_channel_idx = 0;
  26. static_assert((1 << first_channel_idx) & ADC_CHAN_MSK);
  27. ADCSRA &= ~(1 << ADSC); //stop conversion just in case
  28. adc_count = 0;
  29. adc_channel = 0;
  30. adc_channel_idx = first_channel_idx;
  31. adc_setmux(adc_channel_idx);
  32. memset((void*)adc_values, 0, sizeof(adc_values));
  33. }
  34. static void adc_setmux(uint8_t ch)
  35. {
  36. ch &= 0x0f;
  37. if (ch & 0x08) ADCSRB |= (1 << MUX5);
  38. else ADCSRB &= ~(1 << MUX5);
  39. ADMUX = (ADMUX & ~(0x07)) | (ch & 0x07);
  40. }
  41. void adc_start_cycle() {
  42. adc_reset();
  43. ADCSRA |= (1 << ADSC); //start conversion
  44. }
  45. #ifdef ADC_CALLBACK
  46. extern void ADC_CALLBACK();
  47. #endif //ADC_CALLBACK
  48. ISR(ADC_vect)
  49. {
  50. adc_values[adc_channel] += ADC;
  51. if (++adc_count == ADC_OVRSAMPL)
  52. {
  53. // go to the next channel
  54. if (++adc_channel == ADC_CHAN_CNT) {
  55. #ifdef ADC_CALLBACK
  56. ADC_CALLBACK();
  57. #endif
  58. return; // do not start the next measurement since there are no channels remaining
  59. }
  60. // find the next channel
  61. while (++adc_channel_idx) {
  62. if (ADC_CHAN_MSK & (1 << adc_channel_idx)) {
  63. adc_setmux(adc_channel_idx);
  64. adc_count = 0;
  65. break;
  66. }
  67. }
  68. }
  69. ADCSRA |= (1 << ADSC); //start conversion
  70. }