| /* |
| 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); |
| } |