diff options
Diffstat (limited to 'avr/adc.c')
| -rw-r--r-- | avr/adc.c | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/avr/adc.c b/avr/adc.c new file mode 100644 index 0000000..c21bb8a --- /dev/null +++ b/avr/adc.c @@ -0,0 +1,188 @@ +/************************************************************************/ +/* */ +/* File: avr/adc.c */ +/* Description: analog to digital conversion driver. */ +/* Version: 1.0 */ +/* Author: Otto Mattik */ +/* */ +/* (C)Copyright Otto Mattik 2014-2021. */ +/* */ +/* This file is a part of 'armen' (a tiny operating system). */ +/* 'armen' is distributed under the CeCILL-V2.1 licence. For more */ +/* details about this licence, please visit the website cecill.info */ +/* */ +/************************************************************************/ + +#ifndef AVR_GPIO_C + #error "do not use this code directly, it must be included via gpio.c" +#endif + +static uint8_t adc_def = 0; +static uint8_t adc_ref = 0; + +/* + * set refefence voltage for analog conversion + * + * it is assumed than if AVCC exist, it is connected to + * +5V supply and AREF is decoupled by a capacitor. + * + * +5V + * | + * +--> AVCC + * + * +--> AREF + * | + * --- + * 100nF + * --- + * | + * GND +*/ +void gpio_adc_ref( uint8_t ref ) +{ +#ifdef CHECK_PARAM + if( ref >= ADC_REF_VCC + #if defined(__AVR_ATtiny841__) + && ADC_REF_INT4V096 + #elif defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny85V__)\ + || defined(__AVR_ATmega2560__) + && ref <= ADC_REF_INT2V56 + #else /* __ATtiny1634__ || __ATmega328P__ */ + && ref <= ADC_REF_INT1V1 + #endif +#endif + ) + { +#if defined(__AVR_ATtiny841__) + if( ref == ADC_REF_VCC ) + adc_ref = 0; + else if( ref == ADC_REF_EXT ) + adc_ref = (1<<REFS2); + else if( ref == ADC_REF_INT1V1 ) + adc_ref = (1<<REFS0); + else if( ref == ADC_REF_INT2V2 ) + adc_ref = (1<<REFS1); + else + adc_ref = (1<<REFS1) | (1<<REFS0); +#elif defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny85V__) + if( ref == ADC_REF_VCC ) + adc_ref = 0; + else if( ref == ADC_REF_EXT ) + adc_ref = (1<<REFS0); + else if( ref == ADC_REF_INT1V1 ) + adc_ref = (1<<REFS1); + else + adc_ref = (1<<REFS2) | (1<<REFS1); +#elif defined(__AVR_ATtiny1634__) + if( ref == ADC_REF_VCC ) + adc_ref = 0; + else if( ref == ADC_REF_EXT ) + adc_ref = (1<<REFS0); + else + adc_ref = (1<<REFS1); +#elif defined(__AVR_ATmega2560__) + if( ref == ADC_REF_VCC ) + adc_ref = (1<<REFS0); + else if( ref == ADC_REF_EXT ) + adc_ref = 0; + else if( ref == ADC_REF_INT1V1 ) + adc_ref = (1<<REFS1); + else + adc_ref = (1<<REFS1) | (1<<REFS0); +#else /* __ATmega328P__ */ + if( ref == ADC_REF_VCC ) + adc_ref = (1<<REFS0); + else if( ref == ADC_REF_EXT ) + adc_ref = 0; + else + adc_ref = (1<<REFS1) | (1<<REFS0); +#endif + adc_def = 1; + } +} + +/* + * read value of an analog gpio pin + * + * input: + * gpio gpio pin + * output: + * adc conversion if success, otherwise -1 +*/ +int16_t gpio_adc_get( uint8_t gpio ) +{ + uint16_t value = -1; + uint8_t prescale = +#if (FCPU <= 400000UL) + 1; +#elif (F_CPU <= 800000UL) + 2; +#elif (F_CPU <= 1600000UL) + 3; +#elif (F_CPU <= 3200000UL) + 4; +#elif (F_CPU <= 6400000UL) + 5; +#elif (F_CPU <= 12800000UL) + 6; +#else + 7; +#endif + +#ifdef CHECK_PARAM + if( gpio < (GPIO_MAX_PORT << 3) ) +#endif + { +#if defined(__AVR_ATtiny84__) + if( gpio <= 7 ) + { +#elif defined(__AVR_ATtiny85__) + if( gpio >= 2 && gpio <= 5 ) + { + if( gpio == 2 || gpio == 4) + gpio >>= 1; + else if( gpio == 5 ) + gpio = 0; +#elif defined(__AVR_ATtiny1634__) + if( (gpio >= 3 && gpio <= 11) + || (gpio >= 16 && gpio <= 18) ) + { + gpio -= (gpio >= 16 ? 7 : 3); +#elif defined(__AVR_ATmega328P__) + /* ADC6 and ADC7 are not implemented */ + if( gpio >= 8 && gpio <= 13 ) + { + gpio -= 8; +#elif defined(__AVR_ATmega2560__) + if( gpio >= 40 && gpio <= 47 ) + gpio -= 40; + else if( gpio >= 72 && gpio <= 79 ) + gpio -= 64; + else + return( value ); + { +#else + { +#endif + if( adc_def == 0 ) + gpio_adc_ref( ADC_REF_VCC ); + +#if defined(__AVR_ATtiny841__) + ADMUXA = gpio; + ADMUXB = adc_ref; +#elif defined(__AVR_ATmega2560__) + ADMUX = adc_ref | (gpio & 0x07); + ADCSRB &= ~(1<<MUX5); + if( gpio > 8 ) + ADCSRB |= (1<<MUX5); +#else /* __AVR_ATtiny85__ || __AVR_ATtiny1634__ || __ATmega328P__ */ + ADMUX = adc_ref | gpio; +#endif + + ADCSRA = (1<<ADEN) | (1<<ADSC) | prescale; + while( ADCSRA & (1<<ADSC) ) ; + value = ADCW; + } + } + return( value ); +} |
