aboutsummaryrefslogtreecommitdiff
path: root/avr/adc.c
diff options
context:
space:
mode:
Diffstat (limited to 'avr/adc.c')
-rw-r--r--avr/adc.c188
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 );
+}