Skip to content

Commit

Permalink
added the current sensing + phase state for driver
Browse files Browse the repository at this point in the history
  • Loading branch information
askuric committed Jun 16, 2024
1 parent aa8591e commit 5d4187a
Show file tree
Hide file tree
Showing 22 changed files with 390 additions and 225 deletions.
3 changes: 2 additions & 1 deletion src/current_sense/LowsideCurrentSense.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ int LowsideCurrentSense::init(){
// if init failed return fail
if (params == SIMPLEFOC_CURRENT_SENSE_INIT_FAILED) return 0;
// sync the driver
_driverSyncLowSide(driver->params, params);
void* r = _driverSyncLowSide(driver->params, params);
if(r == SIMPLEFOC_CURRENT_SENSE_INIT_FAILED) return 0;
// calibrate zero offsets
calibrateOffsets();
// set the initialized flag
Expand Down
5 changes: 4 additions & 1 deletion src/current_sense/hardware_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@ float _readADCVoltageLowSide(const int pinA, const void* cs_params);
* function syncing the Driver with the ADC for the LowSide Sensing
* @param driver_params - driver parameter structure - hardware specific
* @param cs_params - current sense parameter structure - hardware specific
*
* @return void* - returns the pointer to the current sense parameter structure (unchanged)
* - returns SIMPLEFOC_CURRENT_SENSE_INIT_FAILED if the init fails
*/
void _driverSyncLowSide(void* driver_params, void* cs_params);
void* _driverSyncLowSide(void* driver_params, void* cs_params);

#endif
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include "esp32_adc_driver.h"

#if defined(ESP_H) && defined(ARDUINO_ARCH_ESP32) && defined(SOC_MCPWM_SUPPORTED) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(SIMPLEFOC_ESP32_USELEDC) && 0
#if defined(ESP_H) && defined(ARDUINO_ARCH_ESP32) && defined(SOC_MCPWM_SUPPORTED) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(SIMPLEFOC_ESP32_USELEDC)

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

#include "Arduino.h"

#if defined(ESP_H) && defined(ARDUINO_ARCH_ESP32) && defined(SOC_MCPWM_SUPPORTED) && !defined(SIMPLEFOC_ESP32_USELEDC) && 0
#if defined(ESP_H) && defined(ARDUINO_ARCH_ESP32) && defined(SOC_MCPWM_SUPPORTED) && !defined(SIMPLEFOC_ESP32_USELEDC)
/*
* Get ADC value for pin
* */
Expand Down
189 changes: 189 additions & 0 deletions src/current_sense/hardware_specific/esp32/esp32_mcpwm_mcu.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
#include "../../hardware_api.h"
#include "../../../drivers/hardware_api.h"
#include "../../../drivers/hardware_specific/esp32/esp32_driver_mcpwm.h"
#include "../../../drivers/hardware_specific/esp32/mcpwm_private.h"

#if defined(ESP_H) && defined(ARDUINO_ARCH_ESP32) && defined(SOC_MCPWM_SUPPORTED) && !defined(SIMPLEFOC_ESP32_USELEDC)

// check the version of the ESP-IDF
#include "esp_idf_version.h"

#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
#error SimpleFOC: ESP-IDF version 4 or lower detected. Please update to ESP-IDF 5.x and Arduino-esp32 3.0 (or higher)
#endif


#include "esp32_adc_driver.h"

#include "driver/mcpwm_prelude.h"
#include "soc/mcpwm_reg.h"
#include "soc/mcpwm_struct.h"

#include <soc/sens_reg.h>
#include <soc/sens_struct.h>

#ifdef SIMPLEFOC_ESP32_INTERRUPT_DEBUG
#include "driver/gpio.h"
#endif

#define _ADC_VOLTAGE 3.3f
#define _ADC_RESOLUTION 4095.0f



#define SIMPLEFOC_ESP32_CS_DEBUG(str)\
SIMPLEFOC_ESP32_DEBUG("CS", str);\

#define CHECK_CS_ERR(func_call, message) \
if ((func_call) != ESP_OK) { \
SIMPLEFOC_ESP32_CS_DEBUG("ERROR - " + String(message)); \
return SIMPLEFOC_CURRENT_SENSE_INIT_FAILED; \
}

typedef struct ESP32MCPWMCurrentSenseParams {
int pins[3];
float adc_voltage_conv;
int adc_buffer[3] = {};
int buffer_index = 0;
int no_adc_channels = 0;
} ESP32MCPWMCurrentSenseParams;


/**
* Inline adc reading implementation
*/
// function reading an ADC value and returning the read voltage
float _readADCVoltageInline(const int pinA, const void* cs_params){
uint32_t raw_adc = adcRead(pinA);
return raw_adc * ((ESP32MCPWMCurrentSenseParams*)cs_params)->adc_voltage_conv;
}

// function reading an ADC value and returning the read voltage
void* _configureADCInline(const void* driver_params, const int pinA, const int pinB, const int pinC){


if( _isset(pinA) ) pinMode(pinA, INPUT);
if( _isset(pinB) ) pinMode(pinB, INPUT);
if( _isset(pinC) ) pinMode(pinC, INPUT);

ESP32MCPWMCurrentSenseParams* params = new ESP32MCPWMCurrentSenseParams {
.pins = { pinA, pinB, pinC },
.adc_voltage_conv = (_ADC_VOLTAGE)/(_ADC_RESOLUTION)
};

return params;
}


/**
* Low side adc reading implementation
*/


// function reading an ADC value and returning the read voltage
float _readADCVoltageLowSide(const int pin, const void* cs_params){
ESP32MCPWMCurrentSenseParams* p = (ESP32MCPWMCurrentSenseParams*)cs_params;
int no_channel = 0;
for(int i=0; i < 3; i++){
if(!_isset(p->pins[i])) continue;
if(pin == p->pins[i]) // found in the buffer
return p->adc_buffer[no_channel] * p->adc_voltage_conv;
else no_channel++;
}
// not found
return 0;
}


// function configuring low-side current sensing
void* _configureADCLowSide(const void* driver_params, const int pinA,const int pinB,const int pinC){
// check if driver timer is already running
// fail if it is
// the easiest way that I've found to check if timer is running
// is to start it and stop it
ESP32MCPWMDriverParams *p = (ESP32MCPWMDriverParams*)driver_params;
mcpwm_timer_t* t = (mcpwm_timer_t*) p->timers[0];

// check if low side callback is already set
// if it is, return error
if(t->on_full != nullptr){
SIMPLEFOC_ESP32_CS_DEBUG("Low side callback is already set. Cannot set it again for timer: "+String(t->timer_id)+", group: "+String(t->group->group_id));
return SIMPLEFOC_CURRENT_SENSE_INIT_FAILED;
}

ESP32MCPWMCurrentSenseParams* params = new ESP32MCPWMCurrentSenseParams{};
int no_adc_channels = 0;
if( _isset(pinA) ){
pinMode(pinA, INPUT);
params->pins[no_adc_channels++] = pinA;
}
if( _isset(pinB) ){
pinMode(pinB, INPUT);
params->pins[no_adc_channels++] = pinB;
}
if( _isset(pinC) ){
pinMode(pinC, INPUT);
params->pins[no_adc_channels++] = pinC;
}

t->user_data = params;
params->adc_voltage_conv = (_ADC_VOLTAGE)/(_ADC_RESOLUTION);
params->no_adc_channels = no_adc_channels;
return params;
}

void* _driverSyncLowSide(void* driver_params, void* cs_params){
#ifdef SIMPLEFOC_ESP32_INTERRUPT_DEBUG
pinMode(19, OUTPUT);
#endif
ESP32MCPWMDriverParams *p = (ESP32MCPWMDriverParams*)driver_params;
mcpwm_timer_t* t = (mcpwm_timer_t*) p->timers[0];

// check if low side callback is already set
// if it is, return error
if(t->on_full != nullptr){
SIMPLEFOC_ESP32_CS_DEBUG("Low side callback is already set. Cannot set it again for timer: "+String(t->timer_id)+", group: "+String(t->group->group_id));
return SIMPLEFOC_CURRENT_SENSE_INIT_FAILED;
}

// set the callback for the low side current sensing
// mcpwm_timer_event_callbacks_t can be used to set the callback
// for three timer events
// - on_full - low-side
// - on_empty - high-side
// - on_sync - sync event (not used with simplefoc)
auto cbs = mcpwm_timer_event_callbacks_t{
.on_full = [](mcpwm_timer_handle_t tim, const mcpwm_timer_event_data_t* edata, void* user_data){
ESP32MCPWMCurrentSenseParams *p = (ESP32MCPWMCurrentSenseParams*)user_data;
#ifdef SIMPLEFOC_ESP32_INTERRUPT_DEBUG
gpio_set_level(GPIO_NUM_19,1); //cca 250ns for on+off
#endif
// increment buffer index
p->buffer_index = (p->buffer_index + 1) % p->no_adc_channels;
// sample the phase currents one at a time
// adc read takes around 10us which is very long
// so we are sampling one phase per call
p->adc_buffer[p->buffer_index] = adcRead(p->pins[p->buffer_index]);
#ifdef SIMPLEFOC_ESP32_INTERRUPT_DEBUG
gpio_set_level(GPIO_NUM_19,0); //cca 250ns for on+off
#endif
return true;
},
};
SIMPLEFOC_ESP32_CS_DEBUG("Timer "+String(t->timer_id)+" enable interrupt callback.");
// set the timer state to init (so that we can call the `mcpwm_timer_register_event_callbacks` )
// this is a hack, as this function is not supposed to be called when the timer is running
// the timer does not really go to the init state!
t->fsm = MCPWM_TIMER_FSM_INIT;
// set the callback
CHECK_CS_ERR(mcpwm_timer_register_event_callbacks(t, &cbs, cs_params), "Failed to set low side callback");
// set the timer state to enabled again
t->fsm = MCPWM_TIMER_FSM_ENABLE;
SIMPLEFOC_ESP32_CS_DEBUG("Timer "+String(t->timer_id)+" enable interrupts.");
CHECK_CS_ERR(esp_intr_enable(t->intr), "Failed to enable low-side interrupts!");

return cs_params;
}


#endif
165 changes: 0 additions & 165 deletions src/current_sense/hardware_specific/esp32/esp32_mcu.cpp

This file was deleted.

Loading

0 comments on commit 5d4187a

Please sign in to comment.