From f656f466e7b39a52da3b5c75bc9d02fdbd00c3de Mon Sep 17 00:00:00 2001 From: pulipakaa24 Date: Wed, 21 Jan 2026 00:59:30 -0600 Subject: [PATCH] Implemented oneshot adc reading --- EMG_Arm/src/CMakeLists.txt | 1 + EMG_Arm/src/app/main.c | 63 ++++++++++++++++++---------- EMG_Arm/src/config/config.h | 4 +- EMG_Arm/src/drivers/emg_sensor.c | 70 +++++++++++++++++++++++++++----- 4 files changed, 104 insertions(+), 34 deletions(-) diff --git a/EMG_Arm/src/CMakeLists.txt b/EMG_Arm/src/CMakeLists.txt index 3ca814c..3ddece0 100644 --- a/EMG_Arm/src/CMakeLists.txt +++ b/EMG_Arm/src/CMakeLists.txt @@ -35,4 +35,5 @@ idf_component_register( ${APP_SOURCES} INCLUDE_DIRS . + REQUIRES esp_adc ) diff --git a/EMG_Arm/src/app/main.c b/EMG_Arm/src/app/main.c index 0741168..a8bde15 100644 --- a/EMG_Arm/src/app/main.c +++ b/EMG_Arm/src/app/main.c @@ -273,6 +273,45 @@ static void state_machine_loop(void) } } +void emgPrinter() { + TickType_t previousWake = xTaskGetTickCount(); + while (1) { + emg_sample_t sample; + emg_sensor_read(&sample); + for (uint8_t i = 0; i < EMG_NUM_CHANNELS; i++) { + printf("%d", sample.channels[i]); + if (i != EMG_NUM_CHANNELS - 1) printf(" | "); + } + printf("\n"); + vTaskDelayUntil(&previousWake, pdMS_TO_TICKS(100)); + } +} + +void appConnector() { + /* Create command queue */ + g_cmd_queue = xQueueCreate(10, sizeof(command_t)); + if (g_cmd_queue == NULL) { + printf("[ERROR] Failed to create command queue!\n"); + return; + } + + /* Launch serial input task */ + xTaskCreate( + serial_input_task, + "serial_input", + 4096, /* Stack size */ + NULL, /* Parameters */ + 5, /* Priority */ + NULL /* Task handle */ + ); + + printf("[PROTOCOL] Waiting for host to connect...\n"); + printf("[PROTOCOL] Send: {\"cmd\": \"connect\"}\n\n"); + + /* Run main state machine */ + state_machine_loop(); +} + /******************************************************************************* * Application Entry Point ******************************************************************************/ @@ -300,26 +339,6 @@ void app_main(void) printf("[INIT] Done!\n\n"); - /* Create command queue */ - g_cmd_queue = xQueueCreate(10, sizeof(command_t)); - if (g_cmd_queue == NULL) { - printf("[ERROR] Failed to create command queue!\n"); - return; - } - - /* Launch serial input task */ - xTaskCreate( - serial_input_task, - "serial_input", - 4096, /* Stack size */ - NULL, /* Parameters */ - 5, /* Priority */ - NULL /* Task handle */ - ); - - printf("[PROTOCOL] Waiting for host to connect...\n"); - printf("[PROTOCOL] Send: {\"cmd\": \"connect\"}\n\n"); - - /* Run main state machine */ - state_machine_loop(); + emgPrinter(); + // appConnector(); } diff --git a/EMG_Arm/src/config/config.h b/EMG_Arm/src/config/config.h index 5044d87..521e711 100644 --- a/EMG_Arm/src/config/config.h +++ b/EMG_Arm/src/config/config.h @@ -25,7 +25,7 @@ * Set to 1 while waiting for EMG sensors to arrive. * Set to 0 when ready to use real sensors. */ -#define FEATURE_FAKE_EMG 1 +#define FEATURE_FAKE_EMG 0 /******************************************************************************* * GPIO Pin Definitions - Servos @@ -63,7 +63,7 @@ * EMG Configuration ******************************************************************************/ -#define EMG_NUM_CHANNELS 4 /**< Number of EMG sensor channels */ +#define EMG_NUM_CHANNELS 1 /**< Number of EMG sensor channels */ #define EMG_SAMPLE_RATE_HZ 1000 /**< Samples per second per channel */ /******************************************************************************* diff --git a/EMG_Arm/src/drivers/emg_sensor.c b/EMG_Arm/src/drivers/emg_sensor.c index b63df5e..9cb6e86 100644 --- a/EMG_Arm/src/drivers/emg_sensor.c +++ b/EMG_Arm/src/drivers/emg_sensor.c @@ -8,6 +8,18 @@ #include "emg_sensor.h" #include "esp_timer.h" #include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_adc/adc_oneshot.h" +#include "esp_adc/adc_cali.h" +#include "esp_adc/adc_cali_scheme.h" +#include "esp_err.h" + +adc_oneshot_unit_handle_t adc1_handle; +adc_cali_handle_t cali_handle = NULL; + +const uint8_t emg_channels[EMG_NUM_CHANNELS] = {ADC_CHANNEL_1}; /******************************************************************************* * Public Functions @@ -19,10 +31,44 @@ void emg_sensor_init(void) /* Seed random number generator for fake data */ srand((unsigned int)esp_timer_get_time()); #else - /* TODO: Configure ADC channels when sensors arrive */ - /* adc1_config_width(EMG_ADC_WIDTH); */ - /* adc1_config_channel_atten(ADC_EMG_CH0, EMG_ADC_ATTEN); */ - /* ... */ + // 1. --- ADC Unit Setup --- + adc_oneshot_unit_init_cfg_t init_config1 = { + .unit_id = ADC_UNIT_1, + .ulp_mode = ADC_ULP_MODE_DISABLE, + }; + ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config1, &adc1_handle)); + + // 2. --- ADC Channel Setup (GPIO 1?) --- + // Ensure the channel matches your GPIO in pinmap. For ADC1, GPIO1 is usually not CH0. + // Check your datasheet! (e.g., on S3, GPIO 1 is ADC1_CH0) + adc_oneshot_chan_cfg_t config = { + .bitwidth = ADC_BITWIDTH_DEFAULT, // 12-bit for S3 + .atten = ADC_ATTEN_DB_12, // Allows up to ~3.1V + }; + for (uint8_t i = 0; i < EMG_NUM_CHANNELS; i++) + ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, emg_channels[i], &config)); + + // 3. --- Calibration Setup (CORRECTED for S3) --- + // ESP32-S3 uses Curve Fitting, not Line Fitting + adc_cali_curve_fitting_config_t cali_config = { + .unit_id = ADC_UNIT_1, + .atten = ADC_ATTEN_DB_12, + .bitwidth = ADC_BITWIDTH_DEFAULT, + }; + ESP_ERROR_CHECK(adc_cali_create_scheme_curve_fitting(&cali_config, &cali_handle)); + + // while (1) { + // int raw_val, voltage_mv; + + // // Read Raw + // ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, ADC_CHANNEL_1, &raw_val)); + + // // Convert to mV using calibration + // ESP_ERROR_CHECK(adc_cali_raw_to_voltage(cali_handle, raw_val, &voltage_mv)); + + // printf("Raw: %d | Voltage: %d mV\n", raw_val, voltage_mv); + // vTaskDelay(pdMS_TO_TICKS(500)); + // } #endif } @@ -33,19 +79,23 @@ void emg_sensor_read(emg_sample_t *sample) #if FEATURE_FAKE_EMG /* * Generate fake EMG data: - * - Base value around 512 (middle of 10-bit range, matching Python sim) + * - Base value around 1650 (middle of 3.3V millivolt range) * - Random noise of +/- 50 * - Mimics real EMG baseline noise */ for (int i = 0; i < EMG_NUM_CHANNELS; i++) { int noise = (rand() % 101) - 50; /* -50 to +50 */ - sample->channels[i] = (uint16_t)(512 + noise); + sample->channels[i] = (uint16_t)(1650 + noise); } #else - /* TODO: Real ADC reads when sensors arrive */ - /* sample->channels[0] = adc1_get_raw(ADC_EMG_CH0); */ - /* sample->channels[1] = adc1_get_raw(ADC_EMG_CH1); */ - /* ... */ + int raw_val, voltage_mv; + for (uint8_t i = 0; i < EMG_NUM_CHANNELS; i++) { + ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, emg_channels[i], &raw_val)); + ESP_ERROR_CHECK(adc_cali_raw_to_voltage(cali_handle, raw_val, &voltage_mv)); + sample->channels[i] = (uint16_t) voltage_mv; + } + printf("\n"); + #endif }