diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 4ae563b..6201f50 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.22) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project (growver_firmware) -target_sources(app PRIVATE +target_sources(app PRIVATE src/main.c src/motor.c src/servo.c @@ -17,6 +17,7 @@ target_sources(app PRIVATE src/led_controller.c src/buzzer.c src/uart_commands.c + src/fsr.c ) target_include_directories(app PRIVATE include) \ No newline at end of file diff --git a/app/esp32s3_devkitc_procpu.overlay b/app/esp32s3_devkitc_procpu.overlay index 309400c..7f990e2 100644 --- a/app/esp32s3_devkitc_procpu.overlay +++ b/app/esp32s3_devkitc_procpu.overlay @@ -16,6 +16,7 @@ */ #include +#include /* ----------------------------------------------------------------------- * Pin control — route LEDC channels to physical GPIO pins @@ -42,16 +43,9 @@ input-enable; }; }; - /* ← lsm6dso does NOT belong here */ -}; - -/* lsm6dso goes here instead */ -&i2c0 { - status = "okay"; - pinctrl-0 = <&i2c0_default>; - pinctrl-names = "default"; - clock-frequency = ; + /* Board defines i2c0_default (GPIO1/2) and spim2_default — override them */ + /delete-node/ i2c0_default; i2c0_default: i2c0_default { group1 { pinmux = , @@ -62,6 +56,7 @@ }; // spi for led strip data pin control + /delete-node/ spim2_default; spim2_default: spim2_default { group1 { pinmux = ; @@ -156,4 +151,27 @@ * ----------------------------------------------------------------------- */ &gpio0 { status = "okay"; +}; + +/* ----------------------------------------------------------------------- + * ADC — FSR force sensor on GPIO15 (ADC2 channel 4, Zephyr: adc1 ch4) + * ----------------------------------------------------------------------- */ +/ { + zephyr,user { + io-channels = <&adc1 4>; + }; +}; + +&adc1 { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + channel@4 { + reg = <4>; + zephyr,gain = "ADC_GAIN_1_4"; /* 12 dB atten, ~3.55V full scale */ + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; }; \ No newline at end of file diff --git a/app/include/fsr.h b/app/include/fsr.h new file mode 100644 index 0000000..20bf975 --- /dev/null +++ b/app/include/fsr.h @@ -0,0 +1,20 @@ +#ifndef FSR_H +#define FSR_H + +#include + +/** + * @brief Initialize the FSR ADC channel (GPIO15 / ADC2 CH4). + * @return 0 on success, negative errno on failure. + */ +int fsr_init(void); + +/** + * @brief Read raw ADC count and converted millivolt value in one shot. + * @param raw_out 12-bit raw ADC value (0–4095). + * @param mv_out Voltage in millivolts. + * @return 0 on success, negative errno on failure. + */ +int fsr_read(uint16_t *raw_out, int32_t *mv_out); + +#endif /* FSR_H */ diff --git a/app/prj.conf b/app/prj.conf index e12af33..d7ef534 100644 --- a/app/prj.conf +++ b/app/prj.conf @@ -29,4 +29,5 @@ CONFIG_SHELL_ARGC_MAX=12 CONFIG_SHELL_CMD_BUFF_SIZE=256 CONFIG_KERNEL_SHELL=y -CONFIG_I2C=y \ No newline at end of file +CONFIG_I2C=y +CONFIG_ADC=y \ No newline at end of file diff --git a/app/src/fsr.c b/app/src/fsr.c new file mode 100644 index 0000000..927ae6d --- /dev/null +++ b/app/src/fsr.c @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include "fsr.h" + +LOG_MODULE_REGISTER(fsr, LOG_LEVEL_DBG); + +/* GPIO15 → ESP32-S3 ADC2 channel 4 → Zephyr node adc1, channel 4 */ +static const struct adc_dt_spec fsr_chan = + ADC_DT_SPEC_GET(DT_PATH(zephyr_user)); + +int fsr_init(void) +{ + if (!adc_is_ready_dt(&fsr_chan)) { + LOG_ERR("FSR ADC device not ready"); + return -ENODEV; + } + int ret = adc_channel_setup_dt(&fsr_chan); + if (ret < 0) { + LOG_ERR("FSR ADC channel setup failed: %d", ret); + } + return ret; +} + +int fsr_read(uint16_t *raw_out, int32_t *mv_out) +{ + int16_t buf; + struct adc_sequence seq = { + .buffer = &buf, + .buffer_size = sizeof(buf), + }; + + int ret = adc_sequence_init_dt(&fsr_chan, &seq); + if (ret < 0) { + return ret; + } + + ret = adc_read(fsr_chan.dev, &seq); + if (ret < 0) { + return ret; + } + + *raw_out = (uint16_t)buf; + + int32_t val = buf; + ret = adc_raw_to_millivolts_dt(&fsr_chan, &val); + if (ret < 0) { + return ret; + } + + *mv_out = val; + return 0; +} diff --git a/app/src/main.c b/app/src/main.c index 42721de..d108049 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -8,6 +9,7 @@ #include "motor.h" #include "drive.h" #include "crsf.h" +#include "fsr.h" /* Shared MCU handle — accessible by all threads */ static mcu_t mcu; @@ -28,6 +30,55 @@ void rc_callback(const crsf_channels_t *ch) } +static void i2c_scan(void) +{ + const struct device *i2c_dev = DEVICE_DT_GET(DT_NODELABEL(i2c0)); + + if (!device_is_ready(i2c_dev)) { + printk("I2C0 not ready\n"); + return; + } + + printk("I2C scan:\n"); + int found = 0; + for (uint8_t addr = 0x08; addr <= 0x77; addr++) { + uint8_t dummy; + if (i2c_read(i2c_dev, &dummy, 0, addr) == 0) { + printk(" 0x%02x\n", addr); + found++; + } + } + printk(found ? "%d device(s) found.\n\n" : "No devices found.\n\n", found); +} + +/* ----------------------------------------------------------------------- + * FSR demo thread: logs raw count + millivolts every 500 ms + * ----------------------------------------------------------------------- */ +#define FSR_THREAD_STACK_SIZE 1024 +#define FSR_THREAD_PRIORITY 6 + +K_THREAD_STACK_DEFINE(fsr_stack, FSR_THREAD_STACK_SIZE); +static struct k_thread fsr_thread_data; + +static void fsr_thread_entry(void *p1, void *p2, void *p3) +{ + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + while (1) { + uint16_t raw; + int32_t mv; + + if (fsr_read(&raw, &mv) == 0) { + printk("FSR: raw=%-5u %4d mV\n", raw, mv); + } else { + printk("FSR: read error\n"); + } + k_msleep(500); + } +} + /* ----------------------------------------------------------------------- * Motor thread: runs move_motor's infinite sweep loop * ----------------------------------------------------------------------- */ @@ -79,6 +130,21 @@ int main(void) printk("Motor thread spawned\n"); + /* FSR demo */ + ret = fsr_init(); + if (ret < 0) { + printk("FSR init failed: %d\n", ret); + } else { + k_thread_create(&fsr_thread_data, fsr_stack, + K_THREAD_STACK_SIZEOF(fsr_stack), + fsr_thread_entry, NULL, NULL, NULL, + FSR_THREAD_PRIORITY, 0, K_NO_WAIT); + k_thread_name_set(&fsr_thread_data, "fsr_demo"); + printk("FSR demo thread spawned\n"); + } + + i2c_scan(); + /* * main() must not return — the Zephyr kernel keeps running threads, * but returning from main() on some configs halts the scheduler.