diff --git a/app/Kconfig b/app/Kconfig index e551fa1..fcfc09d 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -81,6 +81,12 @@ config SLEEP_TIME_MS help Duration for which the device will sleep before waking up. This value is in milliseconds. +config ENABLE_ANALOG + bool "Enable Analog Sensor" + default n + help + Enable support for Analog sensor. + source "Kconfig.zephyr" endmenu diff --git a/app/boards/nucleo_wl55jc.overlay b/app/boards/nucleo_wl55jc.overlay index 78486d8..62fffa1 100644 --- a/app/boards/nucleo_wl55jc.overlay +++ b/app/boards/nucleo_wl55jc.overlay @@ -4,6 +4,11 @@ aliases { bme280-i2c = &i2c2; }; + + zephyr,user { + io-channels = <&adc1 6>; + io-channels-names = "a0"; + }; }; &i2c2 { @@ -18,3 +23,18 @@ status = "okay"; }; }; + +&adc1 { + status = "okay"; + + #address-cells = <1>; + #size-cells = <0>; + + soil_sensor: channel@6 { + reg = <6>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; diff --git a/app/prj.conf b/app/prj.conf index 30ae509..2e94ce6 100644 --- a/app/prj.conf +++ b/app/prj.conf @@ -46,4 +46,8 @@ CONFIG_SETTINGS_RUNTIME=y CONFIG_FLASH=y CONFIG_FLASH_MAP=y -CONFIG_BOOTLOADER_MCUBOOT=y \ No newline at end of file +CONFIG_BOOTLOADER_MCUBOOT=y + +# ADC config +CONFIG_ADC=y +CONFIG_CBPRINTF_FP_SUPPORT=y \ No newline at end of file diff --git a/app/protobufs b/app/protobufs index d6c2ed5..2ad0cf8 160000 --- a/app/protobufs +++ b/app/protobufs @@ -1 +1 @@ -Subproject commit d6c2ed5cdf74ffb32790546ed800834908e3d017 +Subproject commit 2ad0cf8d53c186a9fe53f264de15780f4ca91b4b diff --git a/app/src/Application.hpp b/app/src/Application.hpp index 2902b0f..4da4e54 100644 --- a/app/src/Application.hpp +++ b/app/src/Application.hpp @@ -5,7 +5,16 @@ #include "sensor.hpp" // Number of supported sensor types used in the sensors array -#define NUMBER_OF_SENSORS 1 +#define BASE_SENSOR_COUNT 1 + +#ifdef CONFIG_ENABLE_ANALOG + #define ANALOG_SENSOR_COUNT 1 // Analog sensor is enabled +#else + #define ANALOG_SENSOR_COUNT 0 // Analog sensor is disabled +#endif + +// The final fixed size is calculated by the preprocessor +#define NUMBER_OF_SENSORS (BASE_SENSOR_COUNT + ANALOG_SENSOR_COUNT) class LoRaWANHandler; class SleepManager; diff --git a/app/src/main.cpp b/app/src/main.cpp index bbc00dc..75defa0 100644 --- a/app/src/main.cpp +++ b/app/src/main.cpp @@ -3,10 +3,12 @@ #include #include #include +#include #include "Application.hpp" #include "peripherals/lorawan_handler/lorawan_handler.hpp" #include "sensors/bme280/bme280.hpp" +#include "sensors/analog/analog.hpp" #include "sensors/bq27441/bq27441.hpp" #include "utils/banner.hpp" #include "utils/sleep-manager.hpp" @@ -19,14 +21,23 @@ LOG_MODULE_REGISTER(main_entry, LOG_LEVEL_DBG); #define APP_SLEEP_DURATION_MS 10000 #endif +static const struct adc_dt_spec soil_sensor_adc_spec = + ADC_DT_SPEC_GET_BY_IDX(DT_PATH(zephyr_user), 0); + + int main(void) { printk("%s\n", APP_ASCII_BANNER); LOG_INF("===== Buzzverse Node System Booting (Zephyr Log) ====="); BME280 bme280(DEVICE_DT_GET_ANY(bosch_bme280)); + Analog analog(&soil_sensor_adc_spec); + // Array of available sensors etl::array, NUMBER_OF_SENSORS> sensors { etl::unique_ptr(etl::move(&bme280)), +#ifdef CONFIG_ENABLE_ANALOG + etl::unique_ptr(etl::move(&analog)), +#endif }; BQ27441 bq27441(DEVICE_DT_GET_ANY(ti_bq274xx)); diff --git a/app/src/sensors/analog/analog.cpp b/app/src/sensors/analog/analog.cpp new file mode 100644 index 0000000..265ca59 --- /dev/null +++ b/app/src/sensors/analog/analog.cpp @@ -0,0 +1,81 @@ +#include "analog.hpp" + +#include +#include + +#include "buzzverse/analog.pb.h" + +LOG_MODULE_REGISTER(Analog, LOG_LEVEL_DBG); +Analog::Analog(const struct adc_dt_spec* adc_spec) + : m_adc_spec(adc_spec) {} + +using Status = Sensor::Status; + +Peripheral::Status Analog::init() { + if (!m_adc_spec || !device_is_ready(m_adc_spec->dev)) { + status = buzzverse_v1_Status_ComponentState_INITIALIZATION_FAILED; + LOG_WRN("Analog: Analog device not ready or spec is invalid"); + return Peripheral::Status::NOT_READY; + } + + int err = adc_channel_setup_dt(m_adc_spec); + if (err != 0) { + LOG_ERR("Analog: Failed to setup Analog channel %d (err %d)", m_adc_spec->channel_id, err); + status = buzzverse_v1_Status_ComponentState_INITIALIZATION_FAILED; + return Peripheral::Status::INIT_ERR; + } + + LOG_INF("Analog: Analog device ready, channel %d configured via DT", m_adc_spec->channel_id); + status = buzzverse_v1_Status_ComponentState_NORMAL; + + ready = true; + return Peripheral::Status::OK; +} + +Status Analog::read_data(buzzverse_v1_Analog& data) const { + uint16_t sample_buffer = 0; + struct adc_sequence sequence = {0}; + int ret = adc_sequence_init_dt(m_adc_spec, &sequence); + if (ret != 0) { + LOG_ERR("Analog: Failed to initialize Analog sequence: %d", ret); + return Status::READ_ERR; + } + sequence.buffer = &sample_buffer; + sequence.buffer_size = sizeof(sample_buffer); + + ret = adc_read_dt(m_adc_spec, &sequence); + if (ret) { + LOG_ERR("Analog: Analog read failed: %d", ret); + return Status::READ_ERR; + } + + int32_t millivolts = sample_buffer; + ret = adc_raw_to_millivolts_dt(m_adc_spec, &millivolts); + if (ret) { + LOG_ERR("Analog: Failed to convert raw Analog to millivolts: %d", ret); + return Status::READ_ERR; + } + data.millivolts = static_cast(millivolts); + + LOG_DBG("Analog: Raw Analog: %u, Voltage: %u mV", sample_buffer, data.millivolts); + + return Status::OK; +} + +Status Analog::get_packet(buzzverse_v1_Packet& packet) const { + buzzverse_v1_Analog analog_data = buzzverse_v1_Analog_init_zero; + + if(read_data(analog_data) != Sensor::Status::OK) { + return Status::READ_ERR; + } + + packet = buzzverse_v1_Packet_init_default; + packet.which_data = buzzverse_v1_Packet_analog_tag; + packet.data.analog = analog_data; + LOG_DBG("Packet constructed with analog data."); + return Status::OK; +} + +void Analog::get_status(buzzverse_v1_Status& status_message) const { + status_message.analog_status = status; +} \ No newline at end of file diff --git a/app/src/sensors/analog/analog.hpp b/app/src/sensors/analog/analog.hpp new file mode 100644 index 0000000..3973164 --- /dev/null +++ b/app/src/sensors/analog/analog.hpp @@ -0,0 +1,50 @@ +#ifndef ADC_HPP +#define ADC_HPP + +#include +#include +#include + +#include "buzzverse/analog.pb.h" + +#include "../peripherals/peripheral.hpp" +#include "../sensor.hpp" +class Analog : public Sensor { +public: + /** + * @brief Constructor for the Analog sensor. + * @param adc_spec A pointer to the Analog device tree specification struct. + * This is obtained using ADC_DT_SPEC_GET() in your main application. + */ + explicit Analog(const struct adc_dt_spec* adc_spec); + + // Initializes the sensor hardware (ADC channel setup). + Peripheral::Status init() override; + + // Checks if the sensor is ready for reading. + bool is_ready() const override { + return ready; + }; + + // Returns the name of the sensor. + etl::string get_name() const override { + return "Analog"; + } + + Status get_packet(buzzverse_v1_Packet& packet) const override; + + void get_status(buzzverse_v1_Status& status_message) const override; + +private: + buzzverse_v1_Status_ComponentState status{buzzverse_v1_Status_ComponentState_STATE_UNSPECIFIED}; + + // Reads data from the sensor and populates the SoilMoistureData struct. + Sensor::Status read_data(buzzverse_v1_Analog& data) const; + + // A pointer to the ADC specification struct from the device tree. + const struct adc_dt_spec* m_adc_spec; + + bool ready{false}; // Flag to indicate if the sensor is initialized and ready +}; + +#endif \ No newline at end of file diff --git a/app/src/sensors/bme280/bme280.cpp b/app/src/sensors/bme280/bme280.cpp index 6e0117e..309aa57 100644 --- a/app/src/sensors/bme280/bme280.cpp +++ b/app/src/sensors/bme280/bme280.cpp @@ -14,7 +14,7 @@ using Status = Sensor::Status; Peripheral::Status BME280::init() { if (!device_is_ready(bme280_dev)) { LOG_WRN("BME280 device not ready"); - status = buzzverse_v1_Status_ComponentState_INITIALIZATION_FAILED; + status = buzzverse_v1_Status_ComponentState_INITIALIZATION_FAILED; return Peripheral::Status::NOT_READY; } diff --git a/boards/buzzverse/lora_node/lora_node_procpu.dts b/boards/buzzverse/lora_node/lora_node_procpu.dts index 17ca40a..333e317 100644 --- a/boards/buzzverse/lora_node/lora_node_procpu.dts +++ b/boards/buzzverse/lora_node/lora_node_procpu.dts @@ -34,6 +34,11 @@ bq27441-i2c = &i2c0; lora0 = &lora0; }; + + zephyr,user { + io-channels = <&adc1 6>; + io-channels-names = "a0"; + }; leds { compatible = "gpio-leds"; @@ -95,6 +100,31 @@ }; }; +/* ADC pin configuration */ +&pinctrl { + adc_in_pins: adc_in_pins { + pinmux = <&gpio0 8 GPIO_ACTIVE_LOW>; + }; +}; + + +&adc1 { + status = "okay"; + + #address-cells = <1>; + #size-cells = <0>; + + /* Add the label 'soil_sensor' here so the C++ code can find it */ + soil_sensor: channel@6 { + reg = <6>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; + + &spi3 { #address-cells = <1>; #size-cells = <0>; diff --git a/boards/buzzverse/lora_node/lora_node_procpu.yaml b/boards/buzzverse/lora_node/lora_node_procpu.yaml index d9ccf6d..1204966 100644 --- a/boards/buzzverse/lora_node/lora_node_procpu.yaml +++ b/boards/buzzverse/lora_node/lora_node_procpu.yaml @@ -17,6 +17,7 @@ supported: - pwm - dma - lora + - esp32s3-pinctrl testing: ignore_tags: - net