wip: grbl: add support for ADC
diff --git a/grbl/adc.c b/grbl/adc.c
new file mode 100644
index 0000000..660ab3f
--- /dev/null
+++ b/grbl/adc.c
@@ -0,0 +1,559 @@
+/*
+ adc.c - Low level functions for enabling 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/>.
+
+ Conventions:
+ - DEFAULT_ADC_ prefix is reserved for defines from defaults.h
+ - _ prefix for defines function-like
+ - __ prefix for defines variable-like
+ - Switch cases tend to have inline break clause
+ - Fill column size is 80, tab width is 2, always untabified
+ - Single line comment doesn't have trailing full stop
+ - Badly enough, defines are indented, for consistency reasons
+*/
+
+#include "grbl.h"
+
+// First available channel, this is always valid
+#define ADC_DEFAULT_CHANNEL 0
+
+// Max and min number of readings allowed per channel
+#define ADC_MIN_READINGS 1
+#define ADC_MAX_READINGS 16
+#define ADC_MSK_READINGS (DEFAULT_ADC_READINGS - 1)
+
+// Track the ADC status. These are mutually exclusive states
+#define ADC_STATUS_INIT bit(14)
+#define ADC_STATUS_STOP bit(15)
+#define _adc_get_status_module(XX) bit_istrue(adc->s, XX)
+
+// Mutually exclusive states, always clear them first
+#define _adc_set_status_module(XX) \
+ do { \
+ adc->s &= ~(ADC_STATUS_INIT | ADC_STATUS_STOP); \
+ bit_true(adc->s, XX); \
+ } while (0)
+
+// Flag data as reliable
+#define _adc_set_status_channel() \
+ do { \
+ bit_true(adc->s, bit(adc->i_c)); \
+ } while (0)
+
+// Alias current channel being stored in the ADC buffer
+#define __adc_current_channel_avr adc->b[adc->i_c].avr
+
+#ifdef ADC_CONFIG_SYSTEM_ALARM
+ #define __adc_current_channel_min adc->b[adc->i_c].min
+ #define __adc_current_channel_max adc->b[adc->i_c].max
+#endif
+
+#if DEFAULT_ADC_READINGS > 1
+ // isr_next_callback_id is always either 1 or 0, updated dynamically avoids
+ // the need for if-else runtime decision making in the ISR.
+ #define __isr_next_callback_id (adc->i_r & bit(0))
+
+ // Alias for consistency with adc_current_channel_avr
+ #define __adc_current_channel_sum adc->sum
+
+ // Right shift the current reading index, is reset to when reaches bit(0) and
+ // is initialized at DEFAULT_ADC_READINGS.
+ #define _adc_update_index_reading() \
+ do { adc->i_r = adc->i_r >> 1; } while (0)
+
+ // Reset current reading index when beginning reading a new channel
+ #define _adc_reset_index_reading() \
+ do { adc->i_r = DEFAULT_ADC_READINGS; } while (0)
+#endif
+
+// Validate DEFAULT_ADC_READINGS range
+#if (DEFAULT_ADC_READINGS > ADC_MAX_READINGS) || \
+ (DEFAULT_ADC_READINGS < ADC_MIN_READINGS)
+ #error "Invalid DEFAULT_ADC_READINGS"
+
+// Reading once per channel isn't ideal
+#elif DEFAULT_ADC_READINGS == 1
+ #warning "One shot reading is unreliable"
+
+// For accumulation 10 bit (max resolution) times DEFAULT_ADC_READINGS must fit
+// in uint16_t.
+#elif (0x3FF * DEFAULT_ADC_READINGS) >> 16
+ #error "Invalid DEFAULT_ADC_READINGS"
+
+// DEFAULT_ADC_READINGS must be a power of 2
+#elif DEFAULT_ADC_READINGS & ADC_MSK_READINGS
+ #error "Invalid DEFAULT_ADC_READINGS"
+#endif
+
+// DEFAULT_ADC_RESOLUTION allowed value is an interger number of bits
+#if DEFAULT_ADC_RESOLUTION == 8
+#elif DEFAULT_ADC_RESOLUTION == 10
+#else
+ #error "Invalid DEFAULT_ADC_RESOLUTION"
+#endif
+
+// DEFAULT_ADC_CHANNELS_MASK, 11-bit, bitmask.
+// The ADC has 11 channels, i-th bit for enabling i-th channel.
+// i.e.
+// 00000001001, enable first and fourth channel,
+// 00000100010, enable second and sixth channel.
+#if !defined(DEFAULT_ADC_CHANNELS_MASK) || (DEFAULT_ADC_CHANNELS_MASK == 0) || \
+ (DEFAULT_ADC_CHANNELS_MASK >> ADC_CONFIG_CHANNELS_COUNT)
+ #error "Invalid DEFAULT_ADC_CHANNELS_MASK"
+#endif
+
+// Available and supported modes. Extend this for supporting new modes
+#define MODE0 ADC_CONFIG_MODE_SW_TRIGGER
+#define MODE1 ADC_CONFIG_MODE_HW_TRIGGER
+#if DEFAULT_ADC_MODE == MODE0
+#elif DEFAULT_ADC_MODE == MODE1
+ // In this mode, although possible, isn't reliable to dinamically switch
+ // channel, only allow one channel.
+ #if ADC_CHANNELS_ENABLED_COUNT > 1
+ #error "Invalid ADC_CHANNELS_ENABLED_COUNT"
+ #endif
+#else
+ // None of the above is invalid
+ #error "Invalid DEFAULT_ADC_MODE"
+#endif
+
+// Available ADC clocks. These are the only allowed and implemented
+#if DEFAULT_ADC_CLOCK == 125
+#elif DEFAULT_ADC_CLOCK == 250
+#elif DEFAULT_ADC_CLOCK == 500
+#elif DEFAULT_ADC_CLOCK == 1000
+#elif DEFAULT_ADC_CLOCK == 2000
+#elif DEFAULT_ADC_CLOCK == 4000
+#elif DEFAULT_ADC_CLOCK == 8000
+#else
+ // None of the above is invalid
+ #error "Invalid DEFAULT_ADC_CLOCK"
+#endif
+
+// If the ADC uses 10 bit, only clocks >50Hz and <200Khz are allowed
+#if (DEFAULT_ADC_RESOLUTION != 8) && (DEFAULT_ADC_CLOCK != CLK_125KHZ)
+ #error "Invalid DEFAULT_ADC_CLOCK"
+#endif
+
+// Available ADC inputs for reference voltage. Edit this for supporting new vref
+#if DEFAULT_ADC_REFERENCE == ADC_CONFIG_REFERENCE_INTERNAL_1VREF
+#elif DEFAULT_ADC_REFERENCE == ADC_CONFIG_REFERENCE_INTERNAL_5VREF
+#elif DEFAULT_ADC_REFERENCE == ADC_CONFIG_REFERENCE_EXTERNAL_AVCC
+#else
+ #error "Invalid DEFAULT_ADC_MODE"
+#endif
+
+// Track power reduction status at the moment the ADC module is started
+static uint8_t prr_need_restart;
+adc_data *adc_global;
+
+#ifdef ADC_CONFIG_SYSTEM_ALARM
+// FIXME: move range initialization to settings.c
+//
+// This should really be done in settings.c, as in, min and max should be
+// defined in settings_t. However, for the time being, do NOT write this
+// data to EEPROM, which means rebuild if needed.
+
+#define _set_channel_range(channel, number, MIN, MAX, FLAG) \
+ do { \
+ adc->b[channel].min = (adc_value) (FLAG ? DEFAULT_ADC_RANGE_CHANNEL_ ## number ## _MIN : MIN); \
+ adc->b[channel].max = (adc_value) (FLAG ? DEFAULT_ADC_RANGE_CHANNEL_ ## number ## _MAX : MAX); \
+ } while (0)
+
+static inline void adc_init_range_channel(adc_data *adc)
+{
+ #if ADC_CHANNEL_00_ENABLED
+ _set_channel_range(ADC0, 0, 0, 0, 0);
+ #endif
+ #if ADC_CHANNEL_01_ENABLED
+ _set_channel_range(ADC1, 1, 0, 0, 0);
+ #endif
+ #if ADC_CHANNEL_02_ENABLED
+ _set_channel_range(ADC2, 2, 0, 0, 0);
+ #endif
+ #if ADC_CHANNEL_03_ENABLED
+ _set_channel_range(ADC3, 3, 0, 0, 0);
+ #endif
+ #if ADC_CHANNEL_04_ENABLED
+ _set_channel_range(ADC4, 4, 0, 0, 0);
+ #endif
+ #if ADC_CHANNEL_05_ENABLED
+ _set_channel_range(ADC5, 5, 0, 0, 0);
+ #endif
+ #if ADC_CHANNEL_06_ENABLED
+ _set_channel_range(ADC6, 6, 0, 0, 0);
+ #endif
+ #if ADC_CHANNEL_07_ENABLED
+ _set_channel_range(ADC7, 7, 0, 0, 0);
+ #endif
+ #if ADC_CHANNEL_08_ENABLED
+ _set_channel_range(ADC8, 8, 0, 0, 0);
+ #endif
+ #if ADC_CHANNEL_09_ENABLED
+ _set_channel_range(ADC9, 9, 0, 0, 0);
+ #endif
+ #if ADC_CHANNEL_10_ENABLED
+ _set_channel_range(ADC10, 10, 0, 0, 0);
+ #endif
+}
+#endif
+
+// Switching mode can start a conversion. Check ATMega328p, 7810D–AVR–01/15,
+// page 220. Auto triggering is enabled by setting the ADC auto trigger enable
+// bit, ADATE in ADCSRA. The trigger source is selected by setting the ADC
+// trigger, select bits, ADTS in ADCSRB.
+static inline void adc_init_mode(const int mode)
+{
+ // Trigger bit must be set for any mode but when the next conversion is started
+ // in software.
+ bit_true(ADC_ST1_REG, bit(ADC_ST1_TRIGGER_BIT));
+
+ switch (mode) {
+ case MODE0:
+ bit_false(ADC_ST1_REG, bit(ADC_ST1_TRIGGER_BIT)); break;
+ case MODE1:
+ bit_false(ADC_ST2_REG, ADC_ST2_MODEFR_MASK); break;
+ }
+}
+
+// If the user has a fixed voltage source connected to the AREF pin, the user
+// may not use the other reference voltage options in the application, as they
+// will be shorted to the external voltage.
+static inline void adc_init_reference(const int ref)
+{
+ // Clear all reference bits
+ bit_false(ADC_MUX_REG, ADC_MUX_REFALL_MASK);
+
+ // ATMega328p, 7810D–AVR–01/15, Table 23-3:
+ switch (ref) {
+ case ADC_CONFIG_REFERENCE_INTERNAL_1VREF:
+ bit_true(ADC_MUX_REG, ADC_MUX_REFALL_MASK); break;
+ case ADC_CONFIG_REFERENCE_INTERNAL_5VREF:
+ bit_true(ADC_MUX_REG, ADC_MUX_REFAVC_MASK); break;
+ case ADC_CONFIG_REFERENCE_EXTERNAL_AVCC:
+ bit_true(ADC_MUX_REG, ADC_MUX_REFEXT_MASK); break;
+ }
+}
+
+// ATMega328p, 7810D–AVR–01/15, page 208 says:
+// the successive approximation circuitry requires an input clock frequency
+// between 50kHz and 200kHz to get maximum resolution.
+static inline void adc_init_clock(const int clock)
+{
+ // Clear all clock bits
+ bit_false(ADC_ST1_REG, ADC_ST1_CLKALL_MASK);
+
+ // ATMega328p, 7810D–AVR–01/15, Table 23-5:
+ switch (clock) {
+ case 125: bit_true(ADC_ST1_REG, ADC_ST1_125KHZ_MASK); break;
+ case 250: bit_true(ADC_ST1_REG, ADC_ST1_250KHZ_MASK); break;
+ case 500: bit_true(ADC_ST1_REG, ADC_ST1_500KHZ_MASK); break;
+ case 1000: bit_true(ADC_ST1_REG, ADC_ST1_001MHZ_MASK); break;
+ case 2000: bit_true(ADC_ST1_REG, ADC_ST1_002MHZ_MASK); break;
+ case 4000: bit_true(ADC_ST1_REG, ADC_ST1_004MHZ_MASK); break;
+ case 8000: bit_true(ADC_ST1_REG, ADC_ST1_008MHZ_MASK); break;
+ }
+}
+
+// Check ATMega328p, 7810D–AVR–01/15, page 210, 23.5 and 23.5.1
+static inline void adc_set_channel(const int channel)
+{
+ // Clear all channel bits
+ bit_false(ADC_MUX_REG, ADC_MUX_CHALL_MASK);
+
+ // ATMega328p, 7810D–AVR–01/15, Table 23-4:
+ switch (channel) {
+ #if ADC_CHANNEL_00_ENABLED
+ case ADC0: bit_true(ADC_MUX_REG, ADC_MUX_CH0_MASK); break;
+ #endif
+ #if ADC_CHANNEL_01_ENABLED
+ case ADC1: bit_true(ADC_MUX_REG, ADC_MUX_CH1_MASK); break;
+ #endif
+ #if ADC_CHANNEL_02_ENABLED
+ case ADC2: bit_true(ADC_MUX_REG, ADC_MUX_CH2_MASK); break;
+ #endif
+ #if ADC_CHANNEL_03_ENABLED
+ case ADC3: bit_true(ADC_MUX_REG, ADC_MUX_CH3_MASK); break;
+ #endif
+ #if ADC_CHANNEL_04_ENABLED
+ case ADC4: bit_true(ADC_MUX_REG, ADC_MUX_CH4_MASK); break;
+ #endif
+ #if ADC_CHANNEL_05_ENABLED
+ case ADC5: bit_true(ADC_MUX_REG, ADC_MUX_CH5_MASK); break;
+ #endif
+ #if ADC_CHANNEL_06_ENABLED
+ case ADC6: bit_true(ADC_MUX_REG, ADC_MUX_CH6_MASK); break;
+ #endif
+ #if ADC_CHANNEL_07_ENABLED
+ case ADC7: bit_true(ADC_MUX_REG, ADC_MUX_CH7_MASK); break;
+ #endif
+ #if ADC_CHANNEL_08_ENABLED
+ case ADC8: bit_true(ADC_MUX_REG, ADC_MUX_CHTMP_MASK); break;
+ #endif
+ #if ADC_CHANNEL_09_ENABLED
+ case ADC9: bit_true(ADC_MUX_REG, ADC_MUX_CHGND_MASK); break;
+ #endif
+ #if ADC_CHANNEL_10_ENABLED
+ case ADC10: bit_true(ADC_MUX_REG, ADC_MUX_CHVBG_MASK); break;
+ #endif
+ }
+}
+
+// ATMega328p, 7810D–AVR–01/15, page 208 says:
+// When ADCL is read, the ADC data register is not updated until ADCH is read.
+// Consequently, if the result is left adjusted and no more than 8-bit
+// precision is required, it is sufficient to read ADCH. Otherwise, ADCL must
+// be read first, then ADCH.
+#if DEFAULT_ADC_RESOLUTION == 8
+ static inline uint8_t adc_merge_registers()
+ {
+ return ADC_HGH_REG;
+ }
+#else
+ static inline uint16_t adc_merge_registers()
+ {
+ uint8_t low = ADC_LOW_REG;
+ uint16_t hgh = ((uint16_t) ADC_HGH_REG) << 8;
+ return hgh | low;
+ }
+#endif
+
+#if DEFAULT_ADC_READINGS > 1
+ static inline adc_value adc_get_average(const adc_data *adc)
+ {
+ return (adc_value) (__adc_current_channel_sum / DEFAULT_ADC_READINGS);
+ }
+#else
+ static inline adc_value adc_get_average(const adc_data *adc)
+ {
+ (void)adc;
+
+ return (adc_value) adc_merge_registers();
+ }
+#endif
+
+#if DEFAULT_ADC_MODE == MODE0
+ static inline void adc_set_next_channel(adc_data *adc)
+ {
+ #if ADC_CHANNELS_ENABLED_COUNT & (ADC_CHANNELS_ENABLED_COUNT - 1)
+ adc->i_c = adc->i_c + 1;
+ adc->i_c = adc->i_c % ADC_CHANNELS_ENABLED_COUNT;
+ #else
+ adc->i_c = (adc->i_c + 1) & (ADC_CHANNELS_ENABLED_COUNT - 1);
+ #endif
+ adc_set_channel(adc->i_c);
+ }
+#endif
+
+static inline void adc_kick_conversion()
+{
+ prr_need_restart = ADC_PRR_REG_cpu;
+
+ // Disable power reduction. Note: this register is outside the ADC block
+ bit_false(ADC_PRR_REG_cpu, bit(ADC_PRR_cpu_PRADC_BIT));
+
+ // How long this takes depends on the mode. In single conversion 13.5 cycles
+ bit_true(ADC_ST1_REG, bit(ADC_ST1_START_BIT));
+}
+
+#ifdef ADC_CONFIG_SYSTEM_ALARM
+static inline int adc_need_alarm(const adc_data *adc)
+{
+ const adc_value channel_avr = __adc_current_channel_avr;
+
+ if (channel_avr >= __adc_current_channel_max ||
+ channel_avr <= __adc_current_channel_min)
+ return 1;
+
+ return 0;
+}
+
+static inline void adc_flag_system_alarm(const adc_data *adc)
+{
+ if (sys.state != STATE_ALARM)
+ if (!sys_rt_exec_alarm && adc_need_alarm(adc)) {
+ mc_reset();
+ system_set_exec_alarm(EXEC_ALARM_ADC);
+ }
+}
+#endif
+
+static inline void adc_isr_update_channel_avr(adc_data *adc)
+{
+ // Work out reliable data, not quite so when one-shot reading. Note, change this in
+ // order to use a different method (i.e. filtering).
+ __adc_current_channel_avr = adc_get_average(adc);
+
+ #ifdef ADC_CONFIG_SYSTEM_ALARM
+ // This is called only once every DEFAULT_ADC_READINGS times, data is reliable,
+ // it's a good time to raise an alarm, if any.
+ adc_flag_system_alarm(adc);
+ #endif
+
+ #if DEFAULT_ADC_READINGS > 1
+ // Reset previous sum, prepare for the next channel
+ __adc_current_channel_sum = 0;
+
+ // Wrap reading index for the next channel
+ _adc_reset_index_reading();
+ #endif
+
+ // FIXME: maybe needed for dummy values
+ // Flag data for this channel as reliable
+ _adc_set_status_channel();
+
+ #if DEFAULT_ADC_MODE == MODE0
+ adc_set_next_channel(adc);
+ #endif
+}
+
+static inline void adc_isr_call_read_op(adc_data *adc)
+{
+ #if DEFAULT_ADC_READINGS > 1
+ // Select and call back from the adc struct, do not bother in checking. In
+ // case of abnormal and trusted data this will flag directly the main system
+ // alarm flag, otherwise keep reading until the current channel is drained.
+ adc->isr[__isr_next_callback_id](adc);
+ #else
+ adc_isr_update_channel_avr(adc);
+ #endif
+}
+
+static inline void adc_isr_call_reset_op(adc_data *adc)
+{
+ #if (DEFAULT_ADC_READINGS > 1) && (DEFAULT_ADC_MODE == MODE0)
+ // Start next conversion
+ adc->isr[ADC_ISR_PFN_RST_ID](adc);
+ #elif DEFAULT_ADC_MODE == MODE0
+ (void)adc;
+ // Start next conversion
+ adc_kick_conversion();
+ #endif
+ // No need reset if HW triggering
+}
+
+#if DEFAULT_ADC_READINGS > 1
+ // Callback for ADC_ISR_PFN_SUM_ID
+ static void adc_isr_callback_sum(adc_data *adc)
+ {
+ // Acquire new data
+ __adc_current_channel_sum += adc_merge_registers();
+ _adc_update_index_reading();
+ }
+
+ // Callback for ADC_ISR_PFN_AVR_ID
+ static void adc_isr_callback_avr(adc_data *adc)
+ {
+ adc_isr_update_channel_avr(adc);
+ }
+
+ // Callbacks for ADC_ISR_PFN_RST_ID, only available if SW triggering
+ #if DEFAULT_ADC_MODE == MODE0
+ static void adc_isr_callback_rst(adc_data *adc)
+ {
+ adc_kick_conversion();
+ }
+
+ static void adc_isr_callback_noop() { return; }
+ #endif
+#endif
+
+adc_value adc_read_unsigned(const adc_data *adc, const adc_channel c)
+{
+ return adc->b[c].avr;
+}
+
+void adc_deinit(adc_data *adc)
+{
+ #if (DEFAULT_ADC_MODE == MODE0) && (DEFAULT_ADC_READINGS > 1)
+ // Prevent starting a new conversion in case an IRQ kicks in
+ adc->isr[ADC_ISR_PFN_RST_ID] = adc_isr_callback_noop;
+ #endif
+
+ // Do not turn it back on if it wasn't originally
+ if (bit_istrue(prr_need_restart, bit(ADC_PRR_cpu_PRADC_BIT)))
+ bit_true(ADC_PRR_REG_cpu, bit(ADC_PRR_cpu_PRADC_BIT));
+
+ // Disable the ADC interrupt
+ bit_false(ADC_ST1_REG, bit(ADC_ST1_IRQ_BIT));
+
+ // Disable ADC module
+ bit_false(ADC_ST1_REG, bit(ADC_ST1_ENABLE_BIT));
+}
+
+void adc_init(adc_data *adc)
+{
+ uint8_t i;
+
+ // Init global reference to adc
+ adc_global = adc;
+
+ adc_init_reference(DEFAULT_ADC_REFERENCE);
+ adc_init_clock(DEFAULT_ADC_CLOCK);
+ adc_init_mode(DEFAULT_ADC_MODE);
+
+ #ifdef ADC_CONFIG_SYSTEM_ALARM
+ adc_init_range_channel(adc);
+ #endif
+
+ adc_set_channel(ADC_DEFAULT_CHANNEL);
+
+ #if DEFAULT_ADC_RESOLUTION == 8
+ // Left adjust so to fit in one register only
+ bit_true(ADC_ST1_REG, bit(ADC_ST1_LEFTSHIFT_BIT));
+ #else
+ bit_false(ADC_ST1_REG, bit(ADC_ST1_LEFTSHIFT_BIT));
+ #endif
+
+ #if DEFAULT_ADC_READINGS > 1
+ // i_r is a bit-mask and 1 is left-shifted for DEFAULT_ADC_READINGS
+ // number of times.
+ adc->i_r = DEFAULT_ADC_READINGS;
+ adc->isr[ADC_ISR_PFN_SUM_ID] = adc_isr_callback_sum;
+ adc->isr[ADC_ISR_PFN_AVR_ID] = adc_isr_callback_avr;
+ adc->sum = 0;
+
+ #if (DEFAULT_ADC_MODE == MODE0)
+ adc->isr[ADC_ISR_PFN_RST_ID] = adc_isr_callback_rst;
+ #endif
+ #endif
+
+ adc->i_c = ADC_DEFAULT_CHANNEL;
+ adc->s = ADC_STATUS_INIT;
+
+ // Enable the ADC interrupt
+ bit_true(ADC_ST1_REG, bit(ADC_ST1_IRQ_BIT));
+
+ // This instruction takes 12 ADC clocks to execute
+ bit_true(ADC_ST1_REG, bit(ADC_ST1_ENABLE_BIT));
+
+ // reset buffer's avr, in case of a sys reset and adc_init is called again
+ for (i = 0; i < ADC_CHANNELS_ENABLED_COUNT; i++)
+ adc->b[i].avr = 0;
+
+ // Start the first conversion
+ adc_kick_conversion();
+}
+
+ISR(ADC_vect)
+{
+ adc_isr_call_read_op(adc_global);
+
+ adc_isr_call_reset_op(adc_global);
+}