Move source code to /firmware and fix build paths

This commit is contained in:
2025-05-15 15:51:46 +02:00
parent 6dd4b87a0f
commit 412354fe88
9 changed files with 8 additions and 4 deletions
+18
View File
@@ -0,0 +1,18 @@
FROM ubuntu:22.04
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y \
build-essential \
gcc-avr \
avrdude \
arduino-core-avr \
make \
&& apt-get clean
WORKDIR /usr/src/
COPY . .
RUN make all
CMD ["./main"]
+44
View File
@@ -0,0 +1,44 @@
PROJECT = vase-control
MCU = atmega328p
F_CPU = 16000000UL
CC = avr-gcc
LD = $(CC)
OC = avr-objcopy
RM = rm -f
BUILD_DIR = build
OBJ_DIR = $(BUILD_DIR)/obj
SRCS_C = source/adc.c source/moisture.c source/main.c
OBJS = $(addprefix $(OBJ_DIR)/, $(notdir $(SRCS_C:.c=.o)))
CFLAGS = -Wall -Os -DF_CPU=$(F_CPU) -mmcu=$(MCU) -Iinclude
LDFLAGS = -Wall -Os -mmcu=$(MCU)
LIBS = -lm
EXEC = atmega
ELF_TARGET = $(BUILD_DIR)/$(EXEC).elf
TARGET = $(BUILD_DIR)/$(EXEC).hex
all: $(TARGET)
$(shell mkdir -p $(OBJ_DIR))
$(shell mkdir -p $(BUILD_DIR))
$(ELF_TARGET): $(OBJS)
$(LD) $(LDFLAGS) $(OBJS) -o $@ $(LIBS)
$(OBJ_DIR)/%.o: source/%.c
$(CC) $(CFLAGS) -c $< -o $@
$(TARGET): $(ELF_TARGET)
$(OC) -O ihex -R .eeprom $< $@
clean:
$(RM) $(TARGET) $(ELF_TARGET) $(OBJS)
$(RM) -r $(BUILD_DIR)
.PHONY: all clean
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -e
IMAGE_NAME="vase-control-builder"
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
IMAGE_NAME="vase-control-builder"
DOCKERFILE="$SCRIPT_DIR/Dockerfile"
BUILD_CTX="$SCRIPT_DIR"
DEST_HEX="$SCRIPT_DIR/build/atmega.hex"
MCU="atmega328p"; PRG="usbasp"; AVR_FLAGS="-B 10"
docker build -t "$IMAGE_NAME" -f "$DOCKERFILE" "$BUILD_CTX"
mkdir -p "$(dirname "$DEST_HEX")"
docker run --rm "$IMAGE_NAME" \
cat /usr/src/build/atmega.hex > "$DEST_HEX"
command -v avrdude >/dev/null || { echo "Install avrdude"; exit 1; }
avrdude -v -p m328p -c usbasp -U flash:w:build/atmega.hex:i
+11
View File
@@ -0,0 +1,11 @@
#ifndef ADC_H
#define ADC_H
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
void adcInit(void);
uint16_t adcRead(uint8_t channel);
#endif
+19
View File
@@ -0,0 +1,19 @@
#ifndef CONFIG_H
#define CONFIG_H
#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
#define SENSORS_NUM 6
#endif
+14
View File
@@ -0,0 +1,14 @@
#ifndef MOISTURE_H
#define MOISTURE_H
#include <stdint.h>
#include <stdbool.h>
void initMoistureSensors(void);
void triggerSensorsRead(void);
int16_t moistureSensorsAverage(int8_t sensorPin);
int16_t readMoisture(void);
extern volatile bool readSensors;
#endif
+27
View File
@@ -0,0 +1,27 @@
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
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;
}
+48
View File
@@ -0,0 +1,48 @@
#include <stdint.h>
#include <stdbool.h>
#include <avr/sleep.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>
#include "moisture.h"
#include "adc.h"
ISR(WDT_vect) {
triggerSensorsRead();
}
void watchdogs(void) {
cli();
MCUSR &= ~(1 << WDRF);
WDTCSR |= (1 << WDCE) | (1 << WDE);
WDTCSR = (1 << WDIE) | (1 << WDP3) | (1 << WDP0);
sei();
}
void enterSleep(void) {
set_sleep_mode(SLEEP_MODE_IDLE);
sleep_enable();
sleep_cpu();
sleep_disable();
}
void setup(void) {
adcInit();
initMoistureSensors();
watchdogs();
}
int main(void) {
setup();
while(true) {
if (readSensors) {
int16_t result = readMoisture();
//TODO: send result to esp32
}
// readFromEsp()
// if esp tells to water plants: waterPlants()
enterSleep();
}
return 0;
}
+62
View File
@@ -0,0 +1,62 @@
#include <stdint.h>
#include <stdbool.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include "moisture.h"
#include "config.h"
#include "adc.h"
volatile bool readSensors = false;
void initMoistureSensors(void) {
// Set as input
DDRC &= ~((1 << MOISTURE_SENSOR_A0) |
(1 << MOISTURE_SENSOR_A1) |
(1 << MOISTURE_SENSOR_A2) |
(1 << MOISTURE_SENSOR_A3) |
(1 << MOISTURE_SENSOR_A4) |
(1 << MOISTURE_SENSOR_A5)) ;
//(1 << MOISTURE_SENSOR_A6) |
//(1 << MOISTURE_SENSOR_A7));
// Disable pullup
PORTC &= ~((1 << MOISTURE_SENSOR_A0) |
(1 << MOISTURE_SENSOR_A1) |
(1 << MOISTURE_SENSOR_A2) |
(1 << MOISTURE_SENSOR_A3) |
(1 << MOISTURE_SENSOR_A4) |
(1 << MOISTURE_SENSOR_A5)) ;
//(1 << MOISTURE_SENSOR_A6) |
//(1 << MOISTURE_SENSOR_A7));
}
void triggerSensorsRead(void) {
readSensors = true;
}
int16_t moistureSensorsAverage(int8_t sensorPin) {
int16_t sum = 0;
for (int i = 0; i < SENSOR_READINGS; i++) {
sum += adcRead(sensorPin);
//TODO: implement variance check (if over a certain variance discard measurements for this cycle)
//TODO: maybe add a small delay using watchdog here?
//TODO IMPORTANT: if value < 1 or > 1022, discard that measurement
}
return sum / SENSOR_READINGS;
}
int16_t readMoisture(void) {
uint8_t sensorPins[SENSORS_NUM] = { MOISTURE_SENSOR_A0, MOISTURE_SENSOR_A1,
MOISTURE_SENSOR_A2, MOISTURE_SENSOR_A3,
MOISTURE_SENSOR_A4, MOISTURE_SENSOR_A5 };
//MOISTURE_SENSOR_A6, MOISTURE_SENSOR_A7 };
int16_t overallSum = 0;
for (int i = 0; i < SENSORS_NUM; i++) {
int16_t sensorAverage = moistureSensorsAverage(sensorPins[i]);
//TODO: if a sensor gives 0 or 1023, discard that sensor entirely (means it is disconnected or not working)
overallSum += sensorAverage;
}
return overallSum / SENSORS_NUM;
}