blob: 9e84a386dbc1efd7e41cbff0a6d8501d48f800d5 [file] [log] [blame]
/*
adc.h - Low level header for exposing ADC (Analog Digital Converter)
functionalities
Part of Grbl
Copyright (c) 2019 Luigi Santivetti
Grbl 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.
Grbl 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 Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef adc_h
#define adc_h
#define ADC_CHANNEL_00_ENABLED ((DEFAULT_ADC_CHANNELS_MASK & bit(0)) >> 0)
#define ADC_CHANNEL_01_ENABLED ((DEFAULT_ADC_CHANNELS_MASK & bit(1)) >> 1)
#define ADC_CHANNEL_02_ENABLED ((DEFAULT_ADC_CHANNELS_MASK & bit(2)) >> 2)
#define ADC_CHANNEL_03_ENABLED ((DEFAULT_ADC_CHANNELS_MASK & bit(3)) >> 3)
#define ADC_CHANNEL_04_ENABLED ((DEFAULT_ADC_CHANNELS_MASK & bit(4)) >> 4)
#define ADC_CHANNEL_05_ENABLED ((DEFAULT_ADC_CHANNELS_MASK & bit(5)) >> 5)
#define ADC_CHANNEL_06_ENABLED ((DEFAULT_ADC_CHANNELS_MASK & bit(6)) >> 6)
#define ADC_CHANNEL_07_ENABLED ((DEFAULT_ADC_CHANNELS_MASK & bit(7)) >> 7)
#define ADC_CHANNEL_08_ENABLED ((DEFAULT_ADC_CHANNELS_MASK & bit(8)) >> 8)
#define ADC_CHANNEL_09_ENABLED ((DEFAULT_ADC_CHANNELS_MASK & bit(9)) >> 9)
#define ADC_CHANNEL_10_ENABLED ((DEFAULT_ADC_CHANNELS_MASK & bit(10)) >> 10)
#if DEFAULT_ADC_READINGS > 1
// ADC ISR callbacks
#define ADC_ISR_PFN_SUM_ID 0
#define ADC_ISR_PFN_AVR_ID 1
#if DEFAULT_ADC_MODE == MODE0
#define ADC_ISR_PFN_RST_ID 2
#define ADC_ISR_APFN_COUNT 3
#else
#define ADC_ISR_APFN_COUNT 2
#endif
#endif
// Number of enabled channels
#define ADC_CHANNELS_ENABLED_COUNT \
(ADC_CHANNEL_00_ENABLED + ADC_CHANNEL_01_ENABLED + ADC_CHANNEL_02_ENABLED + \
ADC_CHANNEL_03_ENABLED + ADC_CHANNEL_04_ENABLED + ADC_CHANNEL_05_ENABLED + \
ADC_CHANNEL_06_ENABLED + ADC_CHANNEL_07_ENABLED + ADC_CHANNEL_08_ENABLED + \
ADC_CHANNEL_09_ENABLED + ADC_CHANNEL_10_ENABLED)
// Holding ADC readings
#if DEFAULT_ADC_RESOLUTION == 8
typedef uint8_t adc_value;
#else
typedef uint16_t adc_value;
#endif
typedef struct _adc_data adc_data;
#ifdef ADC_CONFIG_SYSTEM_ALARM
#define ADC_INVALID_RANGE_CHANNEL(NUMBER) \
((!defined(DEFAULT_ADC_RANGE_CHANNEL_ ## NUMBER ## _MIN) || \
!defined(DEFAULT_ADC_RANGE_CHANNEL_ ## NUMBER ## _MAX)) || \
((DEFAULT_ADC_RANGE_CHANNEL_ ## NUMBER ## _MIN >> DEFAULT_ADC_RESOLUTION) || \
(DEFAULT_ADC_RANGE_CHANNEL_ ## NUMBER ## _MAX >> DEFAULT_ADC_RESOLUTION)))
#if ADC_CHANNEL_00_ENABLED && ADC_INVALID_RANGE_CHANNEL(0)
#error "Invalid ADC00 range"
#endif
#if ADC_CHANNEL_01_ENABLED && ADC_INVALID_RANGE_CHANNEL(1)
#error "Invalid ADC01 range"
#endif
#if ADC_CHANNEL_02_ENABLED && ADC_INVALID_RANGE_CHANNEL(2)
#error "Invalid ADC02 range"
#endif
#if ADC_CHANNEL_03_ENABLED && ADC_INVALID_RANGE_CHANNEL(3)
#error "Invalid ADC03 range"
#endif
#if ADC_CHANNEL_04_ENABLED && ADC_INVALID_RANGE_CHANNEL(4)
#error "Invalid ADC04 range"
#endif
#if ADC_CHANNEL_05_ENABLED && ADC_INVALID_RANGE_CHANNEL(5)
#error "Invalid ADC05 range"
#endif
#if ADC_CHANNEL_06_ENABLED && ADC_INVALID_RANGE_CHANNEL(6)
#error "Invalid ADC06 range"
#endif
#if ADC_CHANNEL_07_ENABLED && ADC_INVALID_RANGE_CHANNEL(7)
#error "Invalid ADC07 range"
#endif
#if ADC_CHANNEL_08_ENABLED && ADC_INVALID_RANGE_CHANNEL(8)
#error "Invalid ADC08 range"
#endif
#if ADC_CHANNEL_09_ENABLED && ADC_INVALID_RANGE_CHANNEL(9)
#error "Invalid ADC09 range"
#endif
#if ADC_CHANNEL_10_ENABLED && ADC_INVALID_RANGE_CHANNEL(10)
#error "Invalid ADC10 range"
#endif
#endif
typedef enum {
#if ADC_CHANNEL_00_ENABLED
ADC0,
#endif
#if ADC_CHANNEL_01_ENABLED
ADC1,
#endif
#if ADC_CHANNEL_02_ENABLED
ADC2,
#endif
#if ADC_CHANNEL_03_ENABLED
ADC3,
#endif
#if ADC_CHANNEL_04_ENABLED
ADC4,
#endif
#if ADC_CHANNEL_05_ENABLED
ADC5,
#endif
#if ADC_CHANNEL_06_ENABLED
ADC6,
#endif
#if ADC_CHANNEL_07_ENABLED
ADC7,
#endif
#if ADC_CHANNEL_08_ENABLED
ADC8, // Internal temperature
#endif
#if ADC_CHANNEL_09_ENABLED
ADC9, // Minimum voltage
#endif
#if ADC_CHANNEL_10_ENABLED
ADC10, // Bendgap voltage
#endif
} adc_channel;
struct _adc_data {
#if DEFAULT_ADC_READINGS > 1
// Array of function pointers called back from the ADC ISR and void if-else
void (* isr[ADC_ISR_APFN_COUNT])(adc_data *adc);
// Store partial updates per channel
uint16_t sum;
// Index tracking the current number of reading
uint8_t i_r;
#endif
// Index for the current channel to be stored in the buffer
volatile adc_channel i_c;
// Bitmask for the current status. The first 11 bit are reserved, where the
// i-bit set to 1 flags the i-th channel is drained and the buffer holds
// reliable data. The last 3 bits are for regular ADC ops signalling.
volatile uint16_t s;
// Buffer holding readings per channel
struct {
volatile adc_value avr;
#ifdef ADC_CONFIG_SYSTEM_ALARM
adc_value min;
adc_value max;
#endif
} __attribute__ ((packed)) b[ADC_CHANNELS_ENABLED_COUNT];
} __attribute__ ((packed));
// Setup the ADC with DEFAULTS, enable it and kick a conversion
void adc_init(adc_data *adc);
// Teardown ADC, need to reinit afterwards
void adc_deinit(adc_data *adc);
// Read unsigned ADC buffer value for channel
adc_value adc_read_unsigned(const adc_data *adc, const adc_channel c);
#endif