From 1a10abc4d6b91978fd4e81134067e40bbb459432 Mon Sep 17 00:00:00 2001 From: Erick Ahmed Date: Wed, 14 May 2025 14:36:41 +0200 Subject: [PATCH] Use custom ADC interface using AVR flags --- src/atmega/Makefile | 11 ++++++---- src/atmega/adc.c | 27 +++++++++++++++++++++++++ src/atmega/adc.h | 11 ++++++++++ src/atmega/config.h | 15 ++++++++++++-- src/atmega/{main.cpp => main.c} | 7 ++++--- src/atmega/{moisture.cpp => moisture.c} | 9 +++++---- 6 files changed, 67 insertions(+), 13 deletions(-) create mode 100644 src/atmega/adc.c create mode 100644 src/atmega/adc.h rename src/atmega/{main.cpp => main.c} (90%) rename src/atmega/{moisture.cpp => moisture.c} (80%) diff --git a/src/atmega/Makefile b/src/atmega/Makefile index ba84c74..34660b8 100644 --- a/src/atmega/Makefile +++ b/src/atmega/Makefile @@ -27,9 +27,10 @@ CXXFLAGS = $(CFLAGS) -fno-exceptions -fpermissive -std=gnu++11 LDFLAGS = -Wall -Os -mmcu=$(MCU) -Wl,--gc-sections LIBS = -lm -SRCS_CPP = main.cpp moisture.cpp -HDRS = moisture.h config.h -OBJS = $(addprefix $(OBJ_DIR)/, $(SRCS_CPP:.cpp=.o)) +SRCS_C = adc.c moisture.c main.c +#SRCS_CPP = main.cpp +HDRS = moisture.h config.h adc.h +OBJS = $(addprefix $(OBJ_DIR)/, $(SRCS_CPP:.cpp=.o) $(SRCS_C:.c=.o)) CORE_C_SRCS = \ wiring.c \ @@ -44,7 +45,6 @@ CORE_CPP_SRCS = \ Stream.cpp \ HardwareSerial.cpp \ HardwareSerial0.cpp \ - main.cpp CORE_SRCS = $(addprefix $(ARDUINO_CORE_PATH)/, $(CORE_C_SRCS) $(CORE_CPP_SRCS)) CORE_OBJS = $(patsubst $(ARDUINO_CORE_PATH)/%.c,$(CORE_DIR)/%.o,$(filter %.c,$(CORE_SRCS))) \ @@ -66,6 +66,9 @@ $(ELF_TARGET): $(OBJS) $(CORE_LIB) $(CORE_LIB): $(CORE_OBJS) $(AR) rcs $@ $^ +$(OBJ_DIR)/%.o: %.c $(HDRS) Makefile + $(CC) $(CFLAGS) -c $< -o $@ + $(OBJ_DIR)/%.o: %.cpp $(HDRS) Makefile $(CXX) $(CXXFLAGS) -c $< -o $@ diff --git a/src/atmega/adc.c b/src/atmega/adc.c new file mode 100644 index 0000000..89a5cd9 --- /dev/null +++ b/src/atmega/adc.c @@ -0,0 +1,27 @@ +#include +#include +#include + +void adcInit(void) { + // Set reference voltage to AVcc (REFS0 = 1, REFS1 = 0) + ADMUX = (1 << REFS0); + + // Enable ADC and set prescaler to 128 (for 16 MHz clock, gives 125 kHz ADC clock) + ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); +} + +uint16_t adcRead(uint8_t channel) { + // Select ADC pin (A0-A7) by setting MUX bits in ADMUX + // Pins A6 and A7 would make an 8 sensor array possible (for large vases). + // Achievable only when using the 328p as a DIP, through port C (PC6, PC7) + ADMUX = (ADMUX & 0xF8) | (channel & 0x07); + + // Start conversion + ADCSRA |= (1 << ADSC); + + // Wait for conversion to complete (ADSC becomes '0' when done) + while (ADCSRA & (1 << ADSC)); + + // Read ADC (reading order: ADCL --> ADCH) + return ADC; +} diff --git a/src/atmega/adc.h b/src/atmega/adc.h new file mode 100644 index 0000000..a2ee223 --- /dev/null +++ b/src/atmega/adc.h @@ -0,0 +1,11 @@ +#ifndef ADC_H +#define ADC_H + +#include +#include +#include + +void adcInit(void); +uint16_t adcRead(uint8_t channel); + +#endif diff --git a/src/atmega/config.h b/src/atmega/config.h index d8583ac..7aa0986 100644 --- a/src/atmega/config.h +++ b/src/atmega/config.h @@ -1,7 +1,18 @@ #ifndef CONFIG_H #define CONFIG_H -#define MOISTURE_SENSOR_A0 A0 -#define SENSOR_READINGS 3 +#define MOISTURE_SENSOR_A0 PC0 +#define MOISTURE_SENSOR_A1 PC1 +#define MOISTURE_SENSOR_A2 PC2 +#define MOISTURE_SENSOR_A3 PC3 +#define MOISTURE_SENSOR_A4 PC4 +#define MOISTURE_SENSOR_A5 PC5 +// NOTE: PC6 PC7 are not accessible by default on Arduino Uno R3 +// You need to use the ATMega328p on a custom PCB and use pins 1 and 2 +#define MOISTURE_SENSOR_A6 PC6 +#define MOISTURE_SENSOR_A7 PC7 + + +#define SENSOR_READINGS 5 #endif diff --git a/src/atmega/main.cpp b/src/atmega/main.c similarity index 90% rename from src/atmega/main.cpp rename to src/atmega/main.c index dc9fd2f..ac81129 100644 --- a/src/atmega/main.cpp +++ b/src/atmega/main.c @@ -1,4 +1,3 @@ -#include #include #include #include @@ -26,17 +25,19 @@ void enterSleep(void) { } void setup(void) { - Serial.begin(9600); initMoistureSensor(); watchdogs(); } int main(void) { + setup(); + while(true) { + if (readSensors) { int16_t result = readMoisture(); if (result != -1) { - Serial.println(result); + //Serial.println(result); readSensors = false; } } diff --git a/src/atmega/moisture.cpp b/src/atmega/moisture.c similarity index 80% rename from src/atmega/moisture.cpp rename to src/atmega/moisture.c index 6f5d4bc..64bf6f1 100644 --- a/src/atmega/moisture.cpp +++ b/src/atmega/moisture.c @@ -1,10 +1,10 @@ -#include #include #include #include #include #include "moisture.h" #include "config.h" +#include "adc.h" static int16_t moistureReadingSum = 0; static int8_t moistureReadingCount = 0; @@ -12,7 +12,8 @@ static int8_t moistureReadingCount = 0; volatile bool readSensors = false; void initMoistureSensor(void) { - pinMode(MOISTURE_SENSOR_A0, INPUT); + DDRC &= ~(1 << MOISTURE_SENSOR_A0); // set as input + PORTC &= ~(1 << MOISTURE_SENSOR_A0); //disable pullup } void triggerSensorRead(void) { @@ -23,13 +24,13 @@ int16_t readMoisture(void) { if (!readSensors) return -1; - moistureReadingSum += analogRead(MOISTURE_SENSOR_A0); + adcInit(); + moistureReadingSum += adcRead(MOISTURE_SENSOR_A0); moistureReadingCount++; //TODO: implement variance check (if over a certain variance discard measurements for this cicle) if (moistureReadingCount >= SENSOR_READINGS) { int16_t average = moistureReadingSum / SENSOR_READINGS; - //Serial.println(average); moistureReadingSum = 0; moistureReadingCount = 0; readSensors = false;