From: Gajula, Anish Date: Mon, 24 Nov 2025 07:29:44 +0000 (-0500) Subject: imu works X-Git-Url: https://git.devinivas.org/?a=commitdiff_plain;h=414abdcf69b5ce99833d5dfbee86e1f29bf6650f;p=smartwatch.git imu works hooray!! :D --- diff --git a/.gitignore b/.gitignore index ee59353..d0e8a42 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,6 @@ pytest_embedded_log/ # idf-component-manager output dependencies.lock + +.vscode/ +managed_components/ diff --git a/README b/README index df54834..b6d0209 100644 --- a/README +++ b/README @@ -7,10 +7,48 @@ Authors: Advaith Menon Anish Gajula +Task List +=========== + +Anish +- Pedometer +- Workouts App +- Compass +- RTC & AM/PM logic +- Rings (Move, Exercise, and Standing) (extra) +- Snake Game (extra) +- Messaging (extra) +- 2035le (extra) + +Advaith +- Button Shortcuts +- Simon Says (extra) +- Settings +- Wireless app + + +Together: +- Inkscape for graphics/UI +- Color coded key for button controls +- Haptics +- Battery +- Threads DESCRIPTION =========== +APPS: +Clock face +Pedometer +Settings +Compass +Messaging +Simon Says Color Game +Snake Game +Wireless App (for now) +Wordle game from 2035 +Also have a color coded key for button controls + Startup & Watch Face UI Design the startup and primary display screens on the uLCD (SPI communication). * Display a startup splash screen on boot. @@ -35,6 +73,7 @@ Use IMU for activity recognition. * Detect basic movement for pedometer app. * Differentiate running, walking, and sitting/standing. * Display step count in pedometer app. +* Adding a compass app into the watch Messaging App with Serial Communication Enable messaging functionality between two ESP modules. @@ -49,6 +88,7 @@ Allow user configuration. Battery & Power Efficiency Design to operate using a battery power source. +* Display the battery percentage/charge level * Optimize firmware for low power consumption. * Consider sleep modes and screen power-down. * Manage charging/power regulation. diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index e300e74..47c921f 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,7 +1,9 @@ idf_component_register(SRCS "hello_world_main.c" "goldeloxSerial.c" "task_lcd.c" + "task_imu.c" INCLUDE_DIRS "." PRIV_REQUIRES esp_driver_gpio esp_driver_uart + esp_driver_i2c INCLUDE_DIRS "") diff --git a/main/hello_world_main.c b/main/hello_world_main.c index a823780..c041dfe 100644 --- a/main/hello_world_main.c +++ b/main/hello_world_main.c @@ -11,6 +11,8 @@ #include "freertos/task.h" #include "driver/gpio.h" +/* custom headers we made!!*/ +#include "task_imu.h" #include "pins.h" #include "task_lcd.h" @@ -47,8 +49,8 @@ void app_main(void) gpio_dump_io_configuration(stdout, (1ULL << PIN_VIBRATOR) | (1ULL << PIN_BUTTON_RED)); - lcd_task(); - + // lcd_task(); + task_imu_all(NULL); /* for (int i = 10; i >= 0; i--) { printf("Restarting in %d seconds...\n", i); diff --git a/main/idf_component.yml b/main/idf_component.yml new file mode 100644 index 0000000..e049522 --- /dev/null +++ b/main/idf_component.yml @@ -0,0 +1,18 @@ +## IDF Component Manager Manifest File +dependencies: + ## Required IDF version + idf: + version: '>=4.1.0' + # # Put list of dependencies here + # # For components maintained by Espressif: + # component: "~1.0.0" + # # For 3rd party components: + # username/component: ">=1.0.0,<2.0.0" + # username2/component2: + # version: "~1.0.0" + # # For transient dependencies `public` flag can be set. + # # `public` flag doesn't have an effect dependencies of the `main` component. + # # All dependencies of `main` are public by default. + # public: true + + cybergear-robotics/icm20948: ^0.1.0 diff --git a/main/pins.h b/main/pins.h index 04623f4..da6d148 100644 --- a/main/pins.h +++ b/main/pins.h @@ -15,4 +15,7 @@ #define PIN_ULCD_RX 22 #define PIN_ULCD_RESET 19 +#define PIN_I2C_SDA 4 +#define PIN_I2C_SCL 5 + #endif diff --git a/main/task_imu.c b/main/task_imu.c new file mode 100644 index 0000000..d9435c8 --- /dev/null +++ b/main/task_imu.c @@ -0,0 +1,117 @@ +#include +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/timers.h" + +#include "esp_log.h" +#include "esp_system.h" + +#include "icm20948.h" +#include "icm20948_i2c.h" +#include "pins.h" +#define TAG "i2c_agmt" + +/* i2c bus configuration */ +i2c_config_t conf = { + .mode = I2C_MODE_MASTER, + .sda_io_num = PIN_I2C_SDA, + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_io_num = PIN_I2C_SCL, + .scl_pullup_en = GPIO_PULLUP_ENABLE, + .master.clk_speed = 400000, + .clk_flags = I2C_SCLK_SRC_FLAG_FOR_NOMAL +}; + +/* ICM 20948 configuration */ +icm0948_config_i2c_t icm_config = { + .i2c_port = I2C_NUM_0, + .i2c_addr = ICM_20948_I2C_ADDR_AD1 +}; + + +void print_agmt(icm20948_agmt_t agmt) +{ + ESP_LOGI(TAG, "Acc: [ %d, %d, %d ] Gyr: [ %d, %d, %d ] Mag: [ %d, %d, %d ] Tmp: [ %d ]", + agmt.acc.axes.x, agmt.acc.axes.y, agmt.acc.axes.z, + agmt.gyr.axes.x, agmt.gyr.axes.y, agmt.gyr.axes.z, + agmt.mag.axes.x, agmt.mag.axes.y, agmt.mag.axes.z, + agmt.tmp.val + ); +} + +void task_imu_all(void *) +{ + icm20948_device_t icm; + + /* setup i2c */ + ESP_ERROR_CHECK(i2c_param_config(icm_config.i2c_port, &conf)); + ESP_ERROR_CHECK(i2c_driver_install(icm_config.i2c_port, conf.mode, 0, 0, 0)); + + /* setup ICM20948 device */ + icm20948_init_i2c(&icm, &icm_config); + + /* check ID */ + while (icm20948_check_id(&icm) != ICM_20948_STAT_OK) + { + ESP_LOGE(TAG, "check id failed"); + vTaskDelay(1000 / portTICK_PERIOD_MS); + } + ESP_LOGI(TAG, "check id passed"); + + /* check whoami */ + icm20948_status_e stat = ICM_20948_STAT_ERR; + uint8_t whoami = 0x00; + while ((stat != ICM_20948_STAT_OK) || (whoami != ICM_20948_WHOAMI)) + { + whoami = 0x00; + stat = icm20948_get_who_am_i(&icm, &whoami); + ESP_LOGE(TAG, "whoami does not match (0x %d). Halting...", whoami); + vTaskDelay(1000 / portTICK_PERIOD_MS); + } + + /* Here we are doing a SW reset to make sure the device starts in a known state */ + icm20948_sw_reset(&icm); + vTaskDelay(250 / portTICK_PERIOD_MS); + + icm20948_internal_sensor_id_bm sensors = (icm20948_internal_sensor_id_bm)(ICM_20948_INTERNAL_ACC | ICM_20948_INTERNAL_GYR); + + // Set Gyro and Accelerometer to a particular sample mode + // optiona: SAMPLE_MODE_CONTINUOUS. SAMPLE_MODE_CYCLED + icm20948_set_sample_mode(&icm, sensors, SAMPLE_MODE_CONTINUOUS); + + // Set full scale ranges for both acc and gyr + icm20948_fss_t myfss; + myfss.a = GPM_2; // (icm20948_accel_config_fs_sel_e) + myfss.g = DPS_250; // (icm20948_gyro_config_1_fs_sel_e) + icm20948_set_full_scale(&icm, sensors, myfss); + + // Set up DLPF configuration + icm20948_dlpcfg_t myDLPcfg; + myDLPcfg.a = ACC_D473BW_N499BW; + myDLPcfg.g = GYR_D361BW4_N376BW5; + icm20948_set_dlpf_cfg(&icm, sensors, myDLPcfg); + + // Choose whether or not to use DLPF + icm20948_enable_dlpf(&icm, ICM_20948_INTERNAL_ACC, false); + icm20948_enable_dlpf(&icm, ICM_20948_INTERNAL_GYR, false); + + // Now wake the sensor up + icm20948_sleep(&icm, false); + icm20948_low_power(&icm, false); + + /* loop */ + while(1) + { + vTaskDelay(100 / portTICK_PERIOD_MS); + + icm20948_agmt_t agmt; // = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0}}; + if (icm20948_get_agmt(&icm, &agmt) == ICM_20948_STAT_OK) { + print_agmt(agmt); + } else { + ESP_LOGE(TAG, "Uh oh"); + } + } +} \ No newline at end of file diff --git a/main/task_imu.h b/main/task_imu.h new file mode 100644 index 0000000..9bcd14d --- /dev/null +++ b/main/task_imu.h @@ -0,0 +1,8 @@ +#pragma once + +#ifndef __TASK_IMU_H__ +#define __TASK_IMU_H__ + +void task_imu_all(void *pvParams); + +#endif \ No newline at end of file