From bf974ab871e3be2eabb46be61e1934b8237e16a8 Mon Sep 17 00:00:00 2001
From: Daniel Friesel <derf@finalrewind.org>
Date: Tue, 21 Dec 2021 22:01:43 +0100
Subject: [PATCH] arduino nano adc: add getPin_mV function

---
 include/arch/arduino-nano/driver/adc.h |  1 +
 src/arch/arduino-nano/driver/adc.cc    | 36 ++++++++++++++++++++++++++
 2 files changed, 37 insertions(+)

diff --git a/include/arch/arduino-nano/driver/adc.h b/include/arch/arduino-nano/driver/adc.h
index 30ac338..c89f915 100644
--- a/include/arch/arduino-nano/driver/adc.h
+++ b/include/arch/arduino-nano/driver/adc.h
@@ -17,6 +17,7 @@ class AVRADC {
 
 		int16_t getTemp_mdegC(int16_t offset = 205);
 		uint16_t getVCC_mV();
+		uint16_t getPin_mV(uint8_t pin, uint16_t avcc = 0);
 };
 
 extern AVRADC adc;
diff --git a/src/arch/arduino-nano/driver/adc.cc b/src/arch/arduino-nano/driver/adc.cc
index 17cfc27..8f828a4 100644
--- a/src/arch/arduino-nano/driver/adc.cc
+++ b/src/arch/arduino-nano/driver/adc.cc
@@ -8,6 +8,42 @@
 #include "arch.h"
 #include "driver/adc.h"
 
+uint16_t AVRADC::getPin_mV(uint8_t pin, uint16_t avcc)
+{
+	if (avcc) {
+		// measure with AVCC reference
+		ADMUX = _BV(REFS0) | pin;
+	} else {
+		// measure with internal 1.1V bandgap refernce
+		ADMUX = _BV(REFS1) | _BV(REFS0) | pin;
+	}
+
+	// Enable ADC with /64 prescaler
+	ADCSRA = _BV(ADEN) | _BV(ADPS2);
+
+	// Wait for bandgap to stabilise (70us according to datasheet table 28-3)
+	arch.delay_ms(1);
+
+	// Start conversion
+	ADCSRA |= _BV(ADSC);
+
+	// wait until conversion is complete
+	while (ADCSRA & _BV(ADSC)) ;
+
+	uint8_t adcr_l = ADCL;
+	uint8_t adcr_h = ADCH;
+	uint16_t adcr = adcr_l + (adcr_h << 8);
+
+	// Disable ADC
+	ADCSRA &= ~_BV(ADEN);
+
+	if (avcc) {
+		return (uint32_t)avcc * adcr / 1023L;
+	} else {
+		return 1100L * adcr / 1023L;
+	}
+}
+
 int16_t AVRADC::getTemp_mdegC(int16_t offset)
 {
 	// Measure temperature probe with 1.1V bandgap reference
-- 
GitLab