Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
set(srcs "source/motor_control/esp_foc_core.c"
"source/motor_control/esp_foc_axis_bench.c"
"source/motor_control/esp_foc_estimator_q16.c"
"source/motor_control/esp_foc_biquad_q16.c"
"source/calibration/esp_foc_calibration_format.c"
Expand All @@ -16,7 +17,7 @@ if(ESP_PLATFORM)

idf_build_get_property(target IDF_TARGET)

set(requires esp_driver_uart esp_driver_pcnt esp_driver_gpio esp_driver_mcpwm esp_adc driver freertos esp_system esp_timer nvs_flash)
set(requires esp_driver_uart esp_driver_pcnt esp_driver_gpio esp_driver_mcpwm driver freertos esp_system esp_timer nvs_flash esp_hw_support efuse)
# esp_tinyusb is fetched conditionally for USB-capable targets via
# idf_component.yml; declare the priv require eagerly here so the bridge
# source file finds tinyusb.h on those targets even when the user has not
Expand All @@ -32,9 +33,24 @@ list(APPEND srcs "source/drivers/inverter_3pwm_mcpwm.c"
"source/drivers/rotor_sensor_pcnt.c"
"source/drivers/rotor_sensor_simu.c"
"source/drivers/current_sensor_adc.c"
"source/drivers/esp_foc_adc_cali_lut.c"
"source/drivers/cali/esp_foc_adc_cali_curve.c"
"source/drivers/cali/esp_foc_adc_cali_line.c"
"source/drivers/cali/esp_foc_cali_curve_coeff.c"
"source/drivers/current_sensor_adc_one_shot.c"
"source/osal/os_interface_idf.c")

if(target STREQUAL "esp32")
list(APPEND srcs "source/drivers/isensor_adc_dma_esp32.c")
list(APPEND requires esp_driver_i2s)
elseif(target STREQUAL "esp32s2")
list(APPEND srcs "source/drivers/isensor_adc_dma_esp32s2.c")
list(APPEND requires esp_driver_spi)
else()
list(APPEND srcs "source/drivers/isensor_adc_dma_gdma.c")
list(APPEND requires esp_mm)
endif()

if(CONFIG_ESP_FOC_TUNER_ENABLE)
list(APPEND srcs "source/gui_link/esp_foc_tuner.c"
"source/gui_link/esp_foc_link_session.c")
Expand Down
2 changes: 1 addition & 1 deletion examples/axis_tuning/main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
idf_component_register(SRC_DIRS "."
PRIV_REQUIRES espFoC esp_system freertos esp_driver_i2c esp_adc)
PRIV_REQUIRES espFoC esp_system freertos esp_driver_i2c)
10 changes: 4 additions & 6 deletions examples/axis_tuning/main/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,13 +151,11 @@ void app_main(void)
s_shunts = isensor_adc_oneshot_new(&shunt_cfg, NULL);
#else
esp_foc_isensor_adc_config_t shunt_cfg = {
.axis_channels = {(adc_channel_t)CONFIG_AXIS_TUNING_ISENSE_CH_U,
(adc_channel_t)CONFIG_AXIS_TUNING_ISENSE_CH_V},
.units = {(adc_unit_t)(CONFIG_AXIS_TUNING_ISENSE_ADC_UNIT - 1),
(adc_unit_t)(CONFIG_AXIS_TUNING_ISENSE_ADC_UNIT - 1)},
.amp_gain = (float)CONFIG_AXIS_TUNING_ISENSE_AMP_GAIN_X100 / 100.0f,
.channels = {(adc_channel_t)CONFIG_AXIS_TUNING_ISENSE_CH_U,
(adc_channel_t)CONFIG_AXIS_TUNING_ISENSE_CH_V},
.unit = ADC_UNIT_1,
.amp_gain = (float)CONFIG_AXIS_TUNING_ISENSE_AMP_GAIN_X100 / 100.0f,
.shunt_resistance = (float)CONFIG_AXIS_TUNING_ISENSE_SHUNT_MOHM / 1000.0f,
.number_of_channels = 2,
};
s_shunts = isensor_adc_new(&shunt_cfg);
#endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,10 @@ static esp_foc_isensor_t *shunts;
static void initialize_foc_drivers(void)
{
esp_foc_isensor_adc_config_t shunt_cfg = {
.axis_channels = {ADC_CHANNEL_1, ADC_CHANNEL_5},
.units = {ADC_UNIT_1, ADC_UNIT_1},
.channels = {ADC_CHANNEL_1, ADC_CHANNEL_5},
.unit = ADC_UNIT_1,
.amp_gain = 50.0f,
.shunt_resistance = 0.01f,
.number_of_channels = 2,
};

shunts = isensor_adc_new(&shunt_cfg);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

cmake_minimum_required(VERSION 3.5)

set(EXTRA_COMPONENT_DIRS "./../../../.")

include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(espfoc_isensor_char)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
idf_component_register(SRC_DIRS "."
PRIV_REQUIRES espFoC esp_system freertos)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
source "../../../kconfig/hw_axis_tuning.kconfig"
164 changes: 164 additions & 0 deletions examples/test_drivers/test_isensor_characterize/main/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
/*
* MIT License
*
* Copyright (c) 2021 Felipe Neves
*
* Locked-rotor current-sense characterization: open-loop Vq at fixed theta,
* isensor + inverter on a bench axis exposed to the link layer (tuner/scope).
*
* Workflow:
* 1. Mechanically lock the rotor.
* 2. Flash this firmware and connect espFoC Studio / tunerctl on UART.
* 3. CONNECT → RUN (arms bench, enables inverter) → ramp WRITE UQ.
* 4. SCOPE_START to plot Uq, Iq, Iu, Iv vs time.
* 5. CALISENSOR to re-run DC offset calibration at zero torque.
*
* No encoder and no FOC alignment — the electrical angle is fixed in firmware
* (default 0 rad, tunable via WRITE BENCH_THETA).
*/

#include "esp_log.h"
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "espFoC/esp_foc.h"
#include "espFoC/gui_link/esp_foc_tuner.h"
#include "espFoC/gui_link/esp_foc_link_session.h"
#include "espFoC/inverter_6pwm_mcpwm.h"
#include "espFoC/current_sensor_adc.h"
#include "espFoC/utils/esp_foc_q16.h"

static const char *TAG = "isensor_char";

static esp_foc_axis_t s_axis;
static esp_foc_inverter_t *s_inverter;
static esp_foc_isensor_t *s_shunts;

uint32_t esp_foc_tuner_firmware_type(void)
{
return ESP_FOC_TUNER_FIRMWARE_TYPE_ISCHAR;
}

static int pwm_enable_gpio(void)
{
if (CONFIG_AXIS_TUNING_PWM_EN_PIN < 0) {
return -1;
}
#ifdef CONFIG_AXIS_TUNING_PWM_EN_ACT_LOW
if (CONFIG_AXIS_TUNING_PWM_EN_ACT_LOW) {
return -CONFIG_AXIS_TUNING_PWM_EN_PIN;
}
#endif
return CONFIG_AXIS_TUNING_PWM_EN_PIN;
}

static void wire_scope_channels(void)
{
#if defined(CONFIG_ESP_FOC_SCOPE)
esp_foc_scope_add_channel(&s_axis.u_q.raw, 0);
esp_foc_scope_add_channel(&s_axis.u_d.raw, 1);
esp_foc_scope_add_channel(&s_axis.i_q.raw, 2);
esp_foc_scope_add_channel(&s_axis.i_d.raw, 3);
esp_foc_scope_add_channel(&s_axis.i_u, 4);
esp_foc_scope_add_channel(&s_axis.i_v, 5);
esp_foc_scope_add_channel(&s_axis.latest_i_alpha, 6);
esp_foc_scope_add_channel(&s_axis.latest_i_beta, 7);
esp_foc_scope_initalize();
#endif
}

#if defined(CONFIG_ESP_FOC_SCOPE)
static void pump_scope_idle(void)
{
for (int n = 0; n < CONFIG_ESP_FOC_SCOPE_BUFFER_SIZE; n++) {
esp_foc_scope_data_push();
}
}
#endif

static void bench_task(void *arg)
{
(void)arg;
const TickType_t period = pdMS_TO_TICKS(1);
while (1) {
if (s_axis.state == ESP_FOC_AXIS_STATE_BENCH) {
esp_foc_bench_step(&s_axis);
}
vTaskDelay(period);
}
}

void app_main(void)
{
ESP_LOGI(TAG, "isensor characterization — lock rotor, connect host, arm bench, ramp Uq");

s_inverter = inverter_6pwm_mpcwm_new(
CONFIG_AXIS_TUNING_PWM_U_HI,
CONFIG_AXIS_TUNING_PWM_U_LO,
CONFIG_AXIS_TUNING_PWM_V_HI,
CONFIG_AXIS_TUNING_PWM_V_LO,
CONFIG_AXIS_TUNING_PWM_W_HI,
CONFIG_AXIS_TUNING_PWM_W_LO,
pwm_enable_gpio(),
(float)CONFIG_AXIS_TUNING_DC_LINK_V,
0);
if (s_inverter == NULL) {
ESP_LOGE(TAG, "inverter init failed");
return;
}

esp_foc_isensor_adc_config_t shunt_cfg = {
.channels = {(adc_channel_t)CONFIG_AXIS_TUNING_ISENSE_CH_U,
(adc_channel_t)CONFIG_AXIS_TUNING_ISENSE_CH_V},
.unit = ADC_UNIT_1,
.amp_gain = (float)CONFIG_AXIS_TUNING_ISENSE_AMP_GAIN_X100 / 100.0f,
.shunt_resistance = (float)CONFIG_AXIS_TUNING_ISENSE_SHUNT_MOHM / 1000.0f,
};
s_shunts = isensor_adc_new(&shunt_cfg);
if (s_shunts == NULL) {
ESP_LOGE(TAG, "current sensor init failed");
return;
}

esp_foc_axis_bench_config_t bench_cfg = {
.motor = {
.motor_pole_pairs = CONFIG_AXIS_TUNING_POLE_PAIRS,
.natural_direction = ESP_FOC_MOTOR_NATURAL_DIRECTION_CW,
.motor_unit = 0,
},
.calibrate_isensor_at_init = true,
.bench_theta_e = 0,
};

if (esp_foc_initialize_axis_bench(&s_axis, s_inverter, s_shunts, &bench_cfg) !=
ESP_FOC_OK) {
ESP_LOGE(TAG, "bench axis init failed");
return;
}

wire_scope_channels();
#if defined(CONFIG_ESP_FOC_SCOPE)
pump_scope_idle();
#endif

ESP_ERROR_CHECK(esp_foc_link_attach_axis(0, &s_axis));

if (esp_foc_task_spawn(bench_task, NULL, 4096, 5, NULL) != 0) {
ESP_LOGE(TAG, "bench task spawn failed");
return;
}

ESP_LOGW(TAG,
">>> LOCK the rotor mechanically. Connect Studio/UART. "
"RUN=arm bench, write UQ to stress the windings, SCOPE for I vs U.");

while (1) {
#if defined(CONFIG_ESP_FOC_SCOPE)
if (s_axis.state != ESP_FOC_AXIS_STATE_BENCH) {
pump_scope_idle();
}
#endif
vTaskDelay(pdMS_TO_TICKS(200));
}
}
16 changes: 16 additions & 0 deletions examples/test_drivers/test_isensor_characterize/sdkconfig.defaults
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
CONFIG_ESP_TASK_WDT_EN=n

CONFIG_ESP_FOC_TUNER_ENABLE=y
CONFIG_ESP_FOC_BRIDGE_UART=y
CONFIG_ESP_FOC_BRIDGE_UART_BAUD=921600
CONFIG_ESP_FOC_BRIDGE_UART_TX_PIN=17
CONFIG_ESP_FOC_BRIDGE_UART_RX_PIN=18

CONFIG_ESP_FOC_SCOPE=y
CONFIG_ESP_FOC_SCOPE_NUM_CHANNELS=8
CONFIG_ESP_FOC_SCOPE_BUFFER_SIZE=512

CONFIG_ESP_FOC_PWM_RATE_HZ=20000
CONFIG_ESP_FOC_CALIBRATION_NVS=n

CONFIG_COMPILER_OPTIMIZATION_PERF=y
16 changes: 16 additions & 0 deletions include/espFoC/esp_foc.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,22 @@ esp_foc_err_t esp_foc_initialize_axis(esp_foc_axis_t *axis,
esp_foc_rotor_sensor_t *rotor,
esp_foc_isensor_t *isensor,
esp_foc_motor_control_settings_t settings);

typedef struct {
esp_foc_motor_control_settings_t motor;
bool calibrate_isensor_at_init;
q16_t bench_theta_e;
} esp_foc_axis_bench_config_t;

/** Bench axis: inverter + isensor only (no rotor, no FOC loops). For link/scope characterization. */
esp_foc_err_t esp_foc_initialize_axis_bench(esp_foc_axis_t *axis,
esp_foc_inverter_t *inverter,
esp_foc_isensor_t *isensor,
const esp_foc_axis_bench_config_t *config);

esp_foc_err_t esp_foc_bench_arm(esp_foc_axis_t *axis);
esp_foc_err_t esp_foc_bench_disarm(esp_foc_axis_t *axis);
esp_foc_err_t esp_foc_bench_step(esp_foc_axis_t *axis);
/** Recompute encoder_inv_cpr_q16 after pole pairs or CPR change. */
void esp_foc_axis_refresh_encoder_q16_scales(esp_foc_axis_t *axis);
esp_foc_err_t esp_foc_align_axis(esp_foc_axis_t *axis);
Expand Down
29 changes: 29 additions & 0 deletions include/espFoC/esp_foc_adc_cali_lut.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* MIT License
*
* Copyright (c) 2021 Felipe Neves
*/
#pragma once

#include <stdbool.h>
#include <stdint.h>
#include "hal/adc_types.h"

#define ESP_FOC_ISENSOR_ADC_LUT_SIZE 4096

bool esp_foc_adc_cali_lut_build(adc_unit_t unit,
adc_channel_t channel,
adc_atten_t atten,
int16_t *lut_out,
unsigned lut_len);

static inline int32_t esp_foc_adc_cali_lut_apply(const int16_t *lut, int32_t raw12)
{
if (raw12 < 0) {
raw12 = 0;
}
if (raw12 >= 4096) {
raw12 = 4095;
}
return (int32_t)lut[raw12];
}
2 changes: 2 additions & 0 deletions include/espFoC/esp_foc_axis.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ struct esp_foc_axis_s {
q16_t natural_direction;

esp_foc_axis_state_t state;
esp_foc_axis_mode_t mode;
q16_t bench_theta_e;
volatile bool runner_shutdown;
void *runner_low_speed_hdl;
void *runner_outer_hdl;
Expand Down
7 changes: 7 additions & 0 deletions include/espFoC/esp_foc_err.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ typedef enum {
ESP_FOC_ERR_TIMESTEP_TOO_SMALL = -5,
ESP_FOC_ERR_ROTOR_STARTUP = -6,
ESP_FOC_ERR_ROTOR_STARTUP_PI = -7,
ESP_FOC_ERR_NOT_SUPPORTED = -8,
ESP_FOC_ERR_UNKNOWN = -128
} esp_foc_err_t;

Expand All @@ -27,4 +28,10 @@ typedef enum {
ESP_FOC_AXIS_STATE_ALIGNING = 1,
ESP_FOC_AXIS_STATE_ALIGNED = 2,
ESP_FOC_AXIS_STATE_RUNNING = 3,
ESP_FOC_AXIS_STATE_BENCH = 4,
} esp_foc_axis_state_t;

typedef enum {
ESP_FOC_AXIS_MODE_FOC = 0,
ESP_FOC_AXIS_MODE_BENCH,
} esp_foc_axis_mode_t;
7 changes: 7 additions & 0 deletions include/espFoC/gui_link/esp_foc_link_session.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ void esp_foc_link_session_on_disconnect(void);
void esp_foc_link_session_on_scope_start(void);
void esp_foc_link_session_on_scope_stop(void);

/** Register an axis for tuner/scope/heartbeat (alias of esp_foc_tuner_attach_axis). */
static inline esp_foc_err_t esp_foc_link_attach_axis(uint8_t axis_id,
esp_foc_axis_t *axis)
{
return esp_foc_tuner_attach_axis(axis_id, axis);
}

#ifdef __cplusplus
}
#endif
Loading
Loading