Implemented oneshot adc reading

This commit is contained in:
2026-01-21 00:59:30 -06:00
parent 6734c369b8
commit f656f466e7
4 changed files with 104 additions and 34 deletions

View File

@@ -35,4 +35,5 @@ idf_component_register(
${APP_SOURCES}
INCLUDE_DIRS
.
REQUIRES esp_adc
)

View File

@@ -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();
}

View File

@@ -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 */
/*******************************************************************************

View File

@@ -8,6 +8,18 @@
#include "emg_sensor.h"
#include "esp_timer.h"
#include <stdlib.h>
#include <stdio.h>
#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
}