16b9acf8bc
Read from ADC as fast as possible using the ADC interrupt to get more accurate instantaneous readings. Decouple the temperature_isr from the adc reading interval, so that the two can run independently for future use.
82 lines
2.1 KiB
C++
82 lines
2.1 KiB
C++
#include "adc.h"
|
|
#include <stdio.h>
|
|
#include <avr/io.h>
|
|
#include <avr/interrupt.h>
|
|
#include <avr/pgmspace.h>
|
|
#include <string.h>
|
|
#include "pins.h"
|
|
|
|
static uint8_t adc_count; //used for oversampling
|
|
static uint8_t adc_channel_idx; //bitmask index
|
|
volatile uint8_t adc_channel; //regular index
|
|
volatile uint16_t adc_values[ADC_CHAN_CNT];
|
|
|
|
static void adc_reset();
|
|
static void adc_setmux(uint8_t ch);
|
|
|
|
void adc_init()
|
|
{
|
|
puts_P(PSTR("adc_init"));
|
|
DIDR0 = ((ADC_CHAN_MSK & ADC_DIDR_MSK) & 0xff); //disable digital inputs PORTF
|
|
DIDR2 = ((ADC_CHAN_MSK & ADC_DIDR_MSK) >> 8); //disable digital inputs PORTK
|
|
ADMUX |= (1 << REFS0); //use AVCC as reference
|
|
|
|
//enable ADC, set prescaler/128, enable interrupt
|
|
ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0) | (1 << ADIF) | (1 << ADIE);
|
|
}
|
|
|
|
static void adc_reset()
|
|
{
|
|
static const uint8_t first_channel_idx = 0;
|
|
static_assert((1 << first_channel_idx) & ADC_CHAN_MSK);
|
|
|
|
ADCSRA &= ~(1 << ADSC); //stop conversion just in case
|
|
adc_count = 0;
|
|
adc_channel = 0;
|
|
adc_channel_idx = first_channel_idx;
|
|
adc_setmux(adc_channel_idx);
|
|
memset((void*)adc_values, 0, sizeof(adc_values));
|
|
}
|
|
|
|
static void adc_setmux(uint8_t ch)
|
|
{
|
|
ch &= 0x0f;
|
|
if (ch & 0x08) ADCSRB |= (1 << MUX5);
|
|
else ADCSRB &= ~(1 << MUX5);
|
|
ADMUX = (ADMUX & ~(0x07)) | (ch & 0x07);
|
|
}
|
|
|
|
void adc_start_cycle() {
|
|
adc_reset();
|
|
ADCSRA |= (1 << ADSC); //start conversion
|
|
}
|
|
|
|
#ifdef ADC_CALLBACK
|
|
extern void ADC_CALLBACK();
|
|
#endif //ADC_CALLBACK
|
|
|
|
ISR(ADC_vect)
|
|
{
|
|
adc_values[adc_channel] += ADC;
|
|
if (++adc_count == ADC_OVRSAMPL)
|
|
{
|
|
// go to the next channel
|
|
if (++adc_channel == ADC_CHAN_CNT) {
|
|
#ifdef ADC_CALLBACK
|
|
ADC_CALLBACK();
|
|
#endif
|
|
return; // do not start the next measurement since there are no channels remaining
|
|
}
|
|
|
|
// find the next channel
|
|
while (++adc_channel_idx) {
|
|
if (ADC_CHAN_MSK & (1 << adc_channel_idx)) {
|
|
adc_setmux(adc_channel_idx);
|
|
adc_count = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
ADCSRA |= (1 << ADSC); //start conversion
|
|
}
|