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
20 changes: 16 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ set(requires esp_driver_uart esp_driver_pcnt esp_driver_gpio esp_driver_mcpwm dr
if(target STREQUAL "esp32s2" OR target STREQUAL "esp32s3" OR target STREQUAL "esp32p4")
list(APPEND requires espressif__esp_tinyusb)
endif()
list(APPEND includes "source/drivers")
list(APPEND includes "source/drivers" "source/drivers/cali")
list(APPEND srcs "source/drivers/inverter_3pwm_mcpwm.c"
"source/drivers/inverter_6pwm_mcpwm.c"
"source/drivers/rotor_sensor_as5600.c"
Expand All @@ -35,11 +35,23 @@ list(APPEND srcs "source/drivers/inverter_3pwm_mcpwm.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/drivers/cali/esp_foc_adc_range_extend.c"
"source/osal/os_interface_idf.c")

if(target STREQUAL "esp32")
list(APPEND srcs "source/drivers/cali/esp_foc_adc_cali_line_esp32.c")
elseif(target STREQUAL "esp32s2")
list(APPEND srcs "source/drivers/cali/esp_foc_adc_cali_line_esp32s2.c")
elseif(target STREQUAL "esp32c2")
list(APPEND srcs "source/drivers/cali/esp_foc_adc_cali_line_esp32c2.c")
elseif(EXISTS "${CMAKE_CURRENT_LIST_DIR}/source/drivers/cali/coeff/esp_foc_curve_coeff_${target}.c")
list(APPEND srcs "source/drivers/cali/coeff/esp_foc_curve_coeff_${target}.c")
endif()

if(CONFIG_SOC_ETM_SUPPORTED)
list(APPEND srcs "source/drivers/isensor_adc_etm.c")
endif()

if(target STREQUAL "esp32")
list(APPEND srcs "source/drivers/isensor_adc_dma_esp32.c")
list(APPEND requires esp_driver_i2s)
Expand Down
27 changes: 10 additions & 17 deletions examples/axis_tuning/main/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,9 @@
#elif defined(CONFIG_AXIS_TUNING_ROTOR_SIMU)
#include "espFoC/rotor_sensor_simu.h"
#endif
#if defined(CONFIG_IDF_TARGET_ESP32P4)
#include "espFoC/current_sensor_adc_one_shot.h"
#else
#include "espFoC/current_sensor_adc.h"
#endif
#include "espFoC/utils/esp_foc_q16.h"
#include "soc/soc_caps.h"

static const char *TAG = "axis_tuning";

Expand Down Expand Up @@ -137,19 +134,6 @@ void app_main(void)
return;
}

#if defined(CONFIG_IDF_TARGET_ESP32P4)
esp_foc_isensor_adc_oneshot_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,
.shunt_resistance = (float)CONFIG_AXIS_TUNING_ISENSE_SHUNT_MOHM / 1000.0f,
.number_of_channels = 2,
.enable_analog_encoder = false,
};
s_shunts = isensor_adc_oneshot_new(&shunt_cfg, NULL);
#else
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},
Expand All @@ -158,7 +142,16 @@ void app_main(void)
.shunt_resistance = (float)CONFIG_AXIS_TUNING_ISENSE_SHUNT_MOHM / 1000.0f,
};
s_shunts = isensor_adc_new(&shunt_cfg);
if (s_shunts != NULL) {
#if SOC_ETM_SUPPORTED
esp_foc_isensor_adc_etm_config_t etm_cfg = {
.mcpwm_timer = 0,
.event = ESP_FOC_ISENSOR_ADC_MCPWM_EVT_TIMER_TEZ,
};
esp_foc_isensor_adc_set_etm_source(s_shunts, &etm_cfg);
esp_foc_isensor_adc_set_trigger(s_shunts, ESP_FOC_ISENSOR_ADC_TRIG_ETM);
#endif
}
if (s_shunts == NULL) {
ESP_LOGE(TAG, "current sensor init failed");
return;
Expand Down
52 changes: 37 additions & 15 deletions examples/kconfig/hw_test_encoder.kconfig
Original file line number Diff line number Diff line change
@@ -1,33 +1,55 @@
menu "test_encoder — hardware (SPI AS5048)"
menu "test_encoder — hardware"

config FOC_ENCODER_SDA_PIN
int "I2C SDA (if used; often unused in SPI test)"
choice TEST_ENCODER_SENSOR
prompt "Rotor sensor"
default TEST_ENCODER_AS5600

config TEST_ENCODER_AS5600
bool "AS5600 (I2C)"

config TEST_ENCODER_AS5048
bool "AS5048 (SPI)"
endchoice

config TEST_ENCODER_POLE_PAIRS
int "Motor pole pairs (for electrical angle scale only)"
range 1 64
default 7

config TEST_ENCODER_ENC_SDA
int "AS5600 I2C SDA"
range 0 54
default 8
default 25
depends on TEST_ENCODER_AS5600

config FOC_ENCODER_SCL_PIN
int "I2C SCL (if used)"
config TEST_ENCODER_ENC_SCL
int "AS5600 I2C SCL"
range 0 54
default 9
default 24
depends on TEST_ENCODER_AS5600

config FOC_ENCODER_MISO_PIN
int "SPI MISO"
config TEST_ENCODER_MISO_PIN
int "AS5048 SPI MISO"
range 0 54
default 4
depends on TEST_ENCODER_AS5048

config FOC_ENCODER_MOSI_PIN
int "SPI MOSI"
config TEST_ENCODER_MOSI_PIN
int "AS5048 SPI MOSI"
range 0 54
default 5
depends on TEST_ENCODER_AS5048

config FOC_ENCODER_SCK_PIN
int "SPI SCK"
config TEST_ENCODER_SCK_PIN
int "AS5048 SPI SCK"
range 0 54
default 6
depends on TEST_ENCODER_AS5048

config FOC_ENCODER_CS_PIN
int "SPI CS"
config TEST_ENCODER_CS_PIN
int "AS5048 SPI CS"
range 0 54
default 7
depends on TEST_ENCODER_AS5048

endmenu
4 changes: 2 additions & 2 deletions examples/test_drivers/test_encoder/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

cmake_minimum_required(VERSION 3.5)

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

include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(freerunning_foc)
project(espfoc_encoder_char)
6 changes: 4 additions & 2 deletions examples/test_drivers/test_encoder/main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
idf_component_register(SRCS "test_encoder.c"
INCLUDE_DIRS ".")
set(MOCK_DRIVER_SRC "${CMAKE_CURRENT_LIST_DIR}/../../../../test/mock_drivers.c")

idf_component_register(SRCS "test_encoder.c" "${MOCK_DRIVER_SRC}"
INCLUDE_DIRS "." "${CMAKE_CURRENT_LIST_DIR}/../../../../test")
182 changes: 150 additions & 32 deletions examples/test_drivers/test_encoder/main/test_encoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,56 +2,174 @@
* MIT License
*
* Copyright (c) 2021 Felipe Neves
*
* Encoder characterization: real rotor sensor on a dummy axis (mock inverter +
* mock isensor) exposed to the link layer for counts/degrees verification.
*
* Workflow:
* 1. Flash and connect espFoC Studio / tunerctl on UART.
* 2. CONNECT → SCOPE_START, rotate the shaft by hand.
* 3. Scope channels: raw counts, mech turns, degrees, PLL omega, elec angle.
* 4. READ ENC_COUNTS / ENC_DEG / ENC_TURNS for spot checks.
* 5. EXEC ENC_SET_ZERO to re-zero the encoder.
*/

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

#include "espFoC/rotor_sensor_as5600.h"
#include "espFoC/rotor_sensor_as5048.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/esp_foc_estimator_q16.h"
#include "espFoC/utils/esp_foc_q16.h"
#include "mock_drivers.h"

static const char *TAG = "esp-foc-example";
#if defined(CONFIG_TEST_ENCODER_AS5600)
#include "espFoC/rotor_sensor_as5600.h"
#elif defined(CONFIG_TEST_ENCODER_AS5048)
#include "espFoC/rotor_sensor_as5048.h"
#endif

static const char *TAG = "encoder_char";

static esp_foc_rotor_sensor_t *sensor;
static esp_foc_rotor_sensor_t *sensor2;
static esp_foc_axis_t s_axis;
static mock_inverter_t s_mock_inv;
static mock_isensor_t s_mock_isen;
static esp_foc_rotor_sensor_t *s_rotor;

static q16_t s_enc_deg_q16;
static q16_t s_enc_elec_deg_q16;

static void initialize_foc_drivers(void)
uint32_t esp_foc_tuner_firmware_type(void)
{
sensor = rotor_sensor_as5600_new(
CONFIG_FOC_ENCODER_SDA_PIN,
CONFIG_FOC_ENCODER_SCL_PIN,
0
);

if(sensor == NULL) {
ESP_LOGE(TAG, "failed to create as5600 encoder driver");
}
return ESP_FOC_TUNER_FIRMWARE_TYPE_ENCHAR;
}

sensor2 = rotor_sensor_as5048_new(
CONFIG_FOC_ENCODER_MOSI_PIN,
CONFIG_FOC_ENCODER_MISO_PIN,
CONFIG_FOC_ENCODER_SCK_PIN,
CONFIG_FOC_ENCODER_CS_PIN,
static esp_foc_rotor_sensor_t *encoder_new(void)
{
#if defined(CONFIG_TEST_ENCODER_AS5600)
return rotor_sensor_as5600_new(
CONFIG_TEST_ENCODER_ENC_SDA,
CONFIG_TEST_ENCODER_ENC_SCL,
0);
#elif defined(CONFIG_TEST_ENCODER_AS5048)
return rotor_sensor_as5048_new(
CONFIG_TEST_ENCODER_MOSI_PIN,
CONFIG_TEST_ENCODER_MISO_PIN,
CONFIG_TEST_ENCODER_SCK_PIN,
CONFIG_TEST_ENCODER_CS_PIN,
0,
0
);
0);
#else
return NULL;
#endif
}

if(sensor2 == NULL) {
ESP_LOGE(TAG, "failed to create as5048 encoder driver");
static void encoder_axis_poll(esp_foc_axis_t *axis)
{
if (axis->rotor_sensor_driver == NULL ||
axis->rotor_sensor_driver->read_counts == NULL) {
return;
}

q16_t ticks = axis->rotor_sensor_driver->read_counts(axis->rotor_sensor_driver);
axis->rotor_shaft_ticks = ticks;
axis->rotor_position = ticks;

q16_t theta_mech = q16_normalize_angle(q16_mul(ticks, axis->encoder_inv_cpr_q16));
esp_foc_estimator_q16_set_meas(&axis->rotor_estimator, theta_mech);
esp_foc_estimator_q16_step(&axis->rotor_estimator);

s_enc_deg_q16 = q16_mul(theta_mech, q16_from_float(360.0f));
q16_t theta_elec = esp_foc_estimator_q16_theta_elec(&axis->rotor_estimator);
s_enc_elec_deg_q16 = q16_mul(theta_elec, q16_from_float(360.0f));
}

static void wire_scope_channels(void)
{
#if defined(CONFIG_ESP_FOC_SCOPE)
esp_foc_scope_add_channel(&s_axis.rotor_shaft_ticks, 0);
esp_foc_scope_add_channel(&s_axis.rotor_estimator.theta_meas_mech, 1);
esp_foc_scope_add_channel(&s_enc_deg_q16, 2);
esp_foc_scope_add_channel(&s_axis.rotor_estimator.omega_est_mech, 3);
esp_foc_scope_add_channel(&s_enc_elec_deg_q16, 4);
esp_foc_scope_add_channel(
(const q16_t *)(const volatile void *)&s_axis.rotor_estimator.pll_err, 5);
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 encoder_task(void *arg)
{
(void)arg;
const TickType_t period = pdMS_TO_TICKS(1);
while (1) {
encoder_axis_poll(&s_axis);
vTaskDelay(period);
}
}

void app_main(void)
{
initialize_foc_drivers();

while(1) {
esp_foc_sleep_ms(100);
q16_t r1 = (sensor != NULL) ? sensor->read_counts(sensor) : 0;
q16_t r2 = (sensor2 != NULL) ? sensor2->read_counts(sensor2) : 0;
ESP_LOGI(TAG, "Turn the motor axis by Hand! Encoder reading raw: %f", (double)q16_to_float(r1));
ESP_LOGI(TAG, "Turn the motor axis by Hand! Encoder SPI reading raw: %f", (double)q16_to_float(r2));
ESP_LOGI(TAG, "encoder characterization — connect host, SCOPE, rotate shaft");

mock_inverter_init(&s_mock_inv, 12.0f, (float)CONFIG_ESP_FOC_PWM_RATE_HZ);
mock_isensor_init(&s_mock_isen);

s_rotor = encoder_new();
if (s_rotor == NULL) {
ESP_LOGE(TAG, "encoder driver init failed");
return;
}

esp_foc_motor_control_settings_t settings = {
.motor_pole_pairs = CONFIG_TEST_ENCODER_POLE_PAIRS,
.natural_direction = ESP_FOC_MOTOR_NATURAL_DIRECTION_CW,
.motor_unit = 0,
};

esp_foc_err_t err = esp_foc_initialize_axis(
&s_axis,
mock_inverter_interface(&s_mock_inv),
s_rotor,
mock_isensor_interface(&s_mock_isen),
settings);
if (err != ESP_FOC_OK) {
ESP_LOGE(TAG, "dummy axis init failed: %d", err);
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(encoder_task, NULL, 4096, 5, NULL) != 0) {
ESP_LOGE(TAG, "encoder poll task spawn failed");
return;
}

ESP_LOGW(TAG,
">>> Rotate the shaft. CONNECT + SCOPE_START on UART. "
"READ 0x0057=counts 0x0058=deg 0x0059=turns. EXEC 0x00A6=zero.");

while (1) {
#if defined(CONFIG_ESP_FOC_SCOPE)
pump_scope_idle();
#endif
vTaskDelay(pdMS_TO_TICKS(200));
}
}
Loading
Loading