Skip to content

Commit a7ed4ba

Browse files
committed
an initial implementation of the lowside and inline current sense with the new esp32 api
1 parent e221e06 commit a7ed4ba

13 files changed

+128
-112
lines changed

src/current_sense/hardware_specific/esp32/esp32_adc_driver.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#include "esp32_adc_driver.h"
22

3-
#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
3+
#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)
44

55
#include "freertos/FreeRTOS.h"
66
#include "freertos/task.h"

src/current_sense/hardware_specific/esp32/esp32_adc_driver.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
#include "Arduino.h"
77

8-
#if defined(ESP_H) && defined(ARDUINO_ARCH_ESP32) && defined(SOC_MCPWM_SUPPORTED) && !defined(SIMPLEFOC_ESP32_USELEDC) && 0
8+
#if defined(ESP_H) && defined(ARDUINO_ARCH_ESP32) && defined(SOC_MCPWM_SUPPORTED) && !defined(SIMPLEFOC_ESP32_USELEDC)
99
/*
1010
* Get ADC value for pin
1111
* */

src/current_sense/hardware_specific/esp32/esp32_mcu.cpp

Lines changed: 66 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,26 @@
22
#include "../../../drivers/hardware_api.h"
33
#include "../../../drivers/hardware_specific/esp32/esp32_driver_mcpwm.h"
44

5-
#if defined(ESP_H) && defined(ARDUINO_ARCH_ESP32) && defined(SOC_MCPWM_SUPPORTED) && !defined(SIMPLEFOC_ESP32_USELEDC) && 0
5+
#if defined(ESP_H) && defined(ARDUINO_ARCH_ESP32) && defined(SOC_MCPWM_SUPPORTED) && !defined(SIMPLEFOC_ESP32_USELEDC)
66

7-
#include "esp32_adc_driver.h"
8-
9-
#include "driver/mcpwm.h"
7+
#include "driver/mcpwm_prelude.h"
108
#include "soc/mcpwm_reg.h"
119
#include "soc/mcpwm_struct.h"
12-
1310
#include <soc/sens_reg.h>
1411
#include <soc/sens_struct.h>
1512

1613
#define _ADC_VOLTAGE 3.3f
1714
#define _ADC_RESOLUTION 4095.0f
1815

16+
// set the pin 19 in high during the adc interrupt
17+
// #define SIMPLEFOC_ESP32_INTERRUPT_DEBUG
1918

2019
typedef struct ESP32MCPWMCurrentSenseParams {
2120
int pins[3];
2221
float adc_voltage_conv;
23-
mcpwm_unit_t mcpwm_unit;
24-
int buffer_index;
22+
int adc_buffer[3] = {};
23+
int buffer_index = 0;
24+
int no_adc_channels = 0;
2525
} ESP32MCPWMCurrentSenseParams;
2626

2727

@@ -36,8 +36,8 @@ float _readADCVoltageInline(const int pinA, const void* cs_params){
3636

3737
// function reading an ADC value and returning the read voltage
3838
void* _configureADCInline(const void* driver_params, const int pinA, const int pinB, const int pinC){
39-
_UNUSED(driver_params);
4039

40+
SIMPLEFOC_DEBUG("ESP32-CS: Configuring ADC inline");
4141
if( _isset(pinA) ) pinMode(pinA, INPUT);
4242
if( _isset(pinB) ) pinMode(pinB, INPUT);
4343
if( _isset(pinC) ) pinMode(pinC, INPUT);
@@ -51,30 +51,15 @@ void* _configureADCInline(const void* driver_params, const int pinA, const int p
5151
}
5252

5353

54-
55-
/**
56-
* Low side adc reading implementation
57-
*/
58-
59-
static void IRAM_ATTR mcpwm0_isr_handler(void*);
60-
static void IRAM_ATTR mcpwm1_isr_handler(void*);
61-
byte currentState = 1;
62-
// two mcpwm units
63-
// - max 2 motors per mcpwm unit (6 adc channels)
64-
int adc_pins[2][6]={0};
65-
int adc_pin_count[2]={0};
66-
uint32_t adc_buffer[2][6]={0};
67-
int adc_read_index[2]={0};
68-
6954
// function reading an ADC value and returning the read voltage
7055
float _readADCVoltageLowSide(const int pin, const void* cs_params){
71-
mcpwm_unit_t unit = ((ESP32MCPWMCurrentSenseParams*)cs_params)->mcpwm_unit;
72-
int buffer_index = ((ESP32MCPWMCurrentSenseParams*)cs_params)->buffer_index;
73-
float adc_voltage_conv = ((ESP32MCPWMCurrentSenseParams*)cs_params)->adc_voltage_conv;
74-
75-
for(int i=0; i < adc_pin_count[unit]; i++){
76-
if( pin == ((ESP32MCPWMCurrentSenseParams*)cs_params)->pins[i]) // found in the buffer
77-
return adc_buffer[unit][buffer_index + i] * adc_voltage_conv;
56+
ESP32MCPWMCurrentSenseParams* p = (ESP32MCPWMCurrentSenseParams*)cs_params;
57+
int no_channel = 0;
58+
for(int i=0; i < 3; i++){
59+
if(!_isset(p->pins[i])) continue;
60+
if(pin == p->pins[i]) // found in the buffer
61+
return p->adc_buffer[no_channel] * p->adc_voltage_conv;
62+
else no_channel++;
7863
}
7964
// not found
8065
return 0;
@@ -83,83 +68,68 @@ float _readADCVoltageLowSide(const int pin, const void* cs_params){
8368
// function configuring low-side current sensing
8469
void* _configureADCLowSide(const void* driver_params, const int pinA,const int pinB,const int pinC){
8570

86-
mcpwm_unit_t unit = ((ESP32MCPWMDriverParams*)driver_params)->mcpwm_unit;
87-
int index_start = adc_pin_count[unit];
88-
if( _isset(pinA) ) adc_pins[unit][adc_pin_count[unit]++] = pinA;
89-
if( _isset(pinB) ) adc_pins[unit][adc_pin_count[unit]++] = pinB;
90-
if( _isset(pinC) ) adc_pins[unit][adc_pin_count[unit]++] = pinC;
71+
SIMPLEFOC_DEBUG("ESP32-CS: Configuring ADC low-side");
72+
// check if driver timer is already running
73+
// fail if it is
74+
// the easiest way that I've found to check if timer is running
75+
// is to start it and stop it
76+
ESP32MCPWMDriverParams *p = (ESP32MCPWMDriverParams*)driver_params;
77+
if(mcpwm_timer_start_stop(p->timers[0], MCPWM_TIMER_START_NO_STOP) != ESP_ERR_INVALID_STATE){
78+
// if we get the invalid state error it means that the timer is not enabled
79+
// that means that we can configure it for low-side current sensing
80+
SIMPLEFOC_DEBUG("ESP32-CS: ERR - The timer is already enabled. Cannot be configured for low-side current sensing.");
81+
return SIMPLEFOC_CURRENT_SENSE_INIT_FAILED;
82+
}
9183

92-
if( _isset(pinA) ) pinMode(pinA, INPUT);
93-
if( _isset(pinB) ) pinMode(pinB, INPUT);
94-
if( _isset(pinC) ) pinMode(pinC, INPUT);
9584

96-
ESP32MCPWMCurrentSenseParams* params = new ESP32MCPWMCurrentSenseParams {
97-
.pins = { pinA, pinB, pinC },
98-
.adc_voltage_conv = (_ADC_VOLTAGE)/(_ADC_RESOLUTION),
99-
.mcpwm_unit = unit,
100-
.buffer_index = index_start
101-
};
85+
ESP32MCPWMCurrentSenseParams* params = new ESP32MCPWMCurrentSenseParams{};
86+
int no_adc_channels = 0;
87+
if( _isset(pinA) ){
88+
pinMode(pinA, INPUT);
89+
params->pins[no_adc_channels++] = pinA;
90+
}
91+
if( _isset(pinB) ){
92+
pinMode(pinB, INPUT);
93+
params->pins[no_adc_channels++] = pinB;
94+
}
95+
if( _isset(pinC) ){
96+
pinMode(pinC, INPUT);
97+
params->pins[no_adc_channels++] = pinC;
98+
}
10299

100+
params->adc_voltage_conv = (_ADC_VOLTAGE)/(_ADC_RESOLUTION);
101+
params->no_adc_channels = no_adc_channels;
103102
return params;
104103
}
105104

106105

107106
void _driverSyncLowSide(void* driver_params, void* cs_params){
108-
109-
mcpwm_dev_t* mcpwm_dev = ((ESP32MCPWMDriverParams*)driver_params)->mcpwm_dev;
110-
mcpwm_unit_t mcpwm_unit = ((ESP32MCPWMDriverParams*)driver_params)->mcpwm_unit;
111-
112-
// low-side register enable interrupt
113-
mcpwm_dev->int_ena.timer0_tep_int_ena = true;//A PWM timer 0 TEP event will trigger this interrupt
114-
// high side registers enable interrupt
115-
//mcpwm_dev->int_ena.timer0_tep_int_ena = true;//A PWM timer 0 TEZ event will trigger this interrupt
116-
117-
// register interrupts (mcpwm number, interrupt handler, handler argument = NULL, interrupt signal/flag, return handler = NULL)
118-
if(mcpwm_unit == MCPWM_UNIT_0)
119-
mcpwm_isr_register(mcpwm_unit, mcpwm0_isr_handler, NULL, ESP_INTR_FLAG_IRAM, NULL); //Set ISR Handler
120-
else
121-
mcpwm_isr_register(mcpwm_unit, mcpwm1_isr_handler, NULL, ESP_INTR_FLAG_IRAM, NULL); //Set ISR Handler
122-
}
123-
124-
static void IRAM_ATTR mcpwm0_isr_handler(void*) __attribute__ ((unused));
125-
126-
// Read currents when interrupt is triggered
127-
static void IRAM_ATTR mcpwm0_isr_handler(void*){
128-
// // high side
129-
// uint32_t mcpwm_intr_status = MCPWM0.int_st.timer0_tez_int_st;
107+
#ifdef SIMPLEFOC_ESP32_INTERRUPT_DEBUG
108+
pinMode(19, OUTPUT);
109+
#endif
110+
ESP32MCPWMDriverParams *p = (ESP32MCPWMDriverParams*)driver_params;
130111

131-
// low side
132-
uint32_t mcpwm_intr_status = MCPWM0.int_st.timer0_tep_int_st;
133-
if(mcpwm_intr_status){
134-
adc_buffer[0][adc_read_index[0]] = adcRead(adc_pins[0][adc_read_index[0]]);
135-
adc_read_index[0]++;
136-
if(adc_read_index[0] == adc_pin_count[0]) adc_read_index[0] = 0;
137-
}
138-
// low side
139-
MCPWM0.int_clr.timer0_tep_int_clr = mcpwm_intr_status;
140-
// high side
141-
// MCPWM0.int_clr.timer0_tez_int_clr = mcpwm_intr_status_0;
112+
mcpwm_timer_event_callbacks_t cbs_timer = {
113+
.on_full = [](mcpwm_timer_handle_t tim, const mcpwm_timer_event_data_t* edata, void* user_data){
114+
ESP32MCPWMCurrentSenseParams *p = (ESP32MCPWMCurrentSenseParams*)user_data;
115+
#ifdef SIMPLEFOC_ESP32_INTERRUPT_DEBUG
116+
digitalWrite(19, HIGH);
117+
#endif
118+
// increment buffer index
119+
p->buffer_index = (p->buffer_index + 1) % p->no_adc_channels;
120+
// sample the phase currents one at a time
121+
p->adc_buffer[p->buffer_index] = adcRead(p->pins[p->buffer_index]);
122+
#ifdef SIMPLEFOC_ESP32_INTERRUPT_DEBUG
123+
digitalWrite(19, LOW);
124+
#endif
125+
return true;
126+
}
127+
};
128+
if(mcpwm_timer_register_event_callbacks(p->timers[0], &cbs_timer, cs_params) != ESP_OK){
129+
SIMPLEFOC_DEBUG("ESP32-CS: ERR - Failed to sync ADC and driver");
130+
}
142131
}
143132

144-
static void IRAM_ATTR mcpwm1_isr_handler(void*) __attribute__ ((unused));
145-
146-
// Read currents when interrupt is triggered
147-
static void IRAM_ATTR mcpwm1_isr_handler(void*){
148-
// // high side
149-
// uint32_t mcpwm_intr_status = MCPWM1.int_st.timer0_tez_int_st;
150-
151-
// low side
152-
uint32_t mcpwm_intr_status = MCPWM1.int_st.timer0_tep_int_st;
153-
if(mcpwm_intr_status){
154-
adc_buffer[1][adc_read_index[1]] = adcRead(adc_pins[1][adc_read_index[1]]);
155-
adc_read_index[1]++;
156-
if(adc_read_index[1] == adc_pin_count[1]) adc_read_index[1] = 0;
157-
}
158-
// low side
159-
MCPWM1.int_clr.timer0_tep_int_clr = mcpwm_intr_status;
160-
// high side
161-
// MCPWM1.int_clr.timer0_tez_int_clr = mcpwm_intr_status_0;
162-
}
163133

164134

165135
#endif

src/current_sense/hardware_specific/esp32/esp32s_adc_driver.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#include "esp32_adc_driver.h"
22

3-
#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
3+
#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)
44

55
#include "freertos/FreeRTOS.h"
66
#include "freertos/task.h"

src/drivers/BLDCDriver3PWM.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ BLDCDriver3PWM::BLDCDriver3PWM(int phA, int phB, int phC, int en1, int en2, int
2020

2121
// enable motor driver
2222
void BLDCDriver3PWM::enable(){
23+
// enable hardware if available
24+
_enablePWM(params);
2325
// enable_pin the driver - if enable_pin pin available
2426
if ( _isset(enableA_pin) ) digitalWrite(enableA_pin, enable_active_high);
2527
if ( _isset(enableB_pin) ) digitalWrite(enableB_pin, enable_active_high);

src/drivers/BLDCDriver6PWM.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ BLDCDriver6PWM::BLDCDriver6PWM(int phA_h,int phA_l,int phB_h,int phB_l,int phC_h
2424

2525
// enable motor driver
2626
void BLDCDriver6PWM::enable(){
27+
// enable hardware if available
28+
_enablePWM(params);
2729
// enable_pin the driver - if enable_pin pin available
2830
if ( _isset(enable_pin) ) digitalWrite(enable_pin, enable_active_high);
2931
// set phase state enabled

src/drivers/StepperDriver2PWM.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ StepperDriver2PWM::StepperDriver2PWM(int _pwm1, int _dir1, int _pwm2, int _dir2,
4343

4444
// enable motor driver
4545
void StepperDriver2PWM::enable(){
46+
// enable hardware if available
47+
_enablePWM(params);
4648
// enable_pin the driver - if enable_pin pin available
4749
if ( _isset(enable_pin1) ) digitalWrite(enable_pin1, HIGH);
4850
if ( _isset(enable_pin2) ) digitalWrite(enable_pin2, HIGH);

src/drivers/StepperDriver4PWM.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ StepperDriver4PWM::StepperDriver4PWM(int ph1A,int ph1B,int ph2A,int ph2B,int en1
2020

2121
// enable motor driver
2222
void StepperDriver4PWM::enable(){
23+
// enable hardware if available
24+
_enablePWM(params);
2325
// enable_pin the driver - if enable_pin pin available
2426
if ( _isset(enable_pin1) ) digitalWrite(enable_pin1, HIGH);
2527
if ( _isset(enable_pin2) ) digitalWrite(enable_pin2, HIGH);

src/drivers/hardware_api.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
// flag returned if driver init fails
2929
#define SIMPLEFOC_DRIVER_INIT_FAILED ((void*)-1)
30+
#define SIMPLEFOC_DRIVER_INIT_SUCCESS ((void*)1)
3031

3132
// generic implementation of the hardware specific structure
3233
// containing all the necessary driver parameters
@@ -173,5 +174,15 @@ void _writeDutyCycle4PWM(float dc_1a, float dc_1b, float dc_2a, float dc_2b, vo
173174
*/
174175
void _writeDutyCycle6PWM(float dc_a, float dc_b, float dc_c, PhaseState *phase_state, void* params);
175176

177+
/**
178+
* Function enabling the PWM outputs
179+
* - hardware specific
180+
*
181+
* @param params the driver parameters
182+
*
183+
* @return the pointer to the driver parameters if successful, -1 if failed
184+
*/
185+
void* _enablePWM(void* params);
186+
176187

177188
#endif

src/drivers/hardware_specific/esp32/esp32_driver_mcpwm.cpp

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -320,10 +320,6 @@ void* _configure6PWMPinsMCPWM(long pwm_frequency, int mcpwm_group, int timer_no,
320320
_configureCenterAlign(params->generator[2*i+1],params->comparator[2*i+1], SIMPLEFOC_PWM_LOWSIDE_ACTIVE_HIGH);
321321
}
322322
#endif
323-
SIMPLEFOC_ESP32_DEBUG("Enabling the timer: "+String(timer_no));
324-
// Enable and start timer
325-
CHECK_ERR(mcpwm_timer_enable(params->timers[0]), "Failed to enable timer!");
326-
CHECK_ERR(mcpwm_timer_start_stop(params->timers[0], MCPWM_TIMER_START_NO_STOP), "Failed to start the timer!");
327323

328324
_delay(1);
329325
SIMPLEFOC_ESP32_DEBUG("MCPWM configured!");
@@ -424,12 +420,6 @@ void* _configurePinsMCPWM(long pwm_frequency, int mcpwm_group, int timer_no, int
424420
_configureCenterAlign(params->generator[i],params->comparator[i], !SIMPLEFOC_PWM_ACTIVE_HIGH);
425421
}
426422

427-
SIMPLEFOC_ESP32_DEBUG("Enabling the timer: "+String(timer_no));
428-
// Enable and start timer if not shared
429-
if (!shared_timer) CHECK_ERR(mcpwm_timer_enable(params->timers[0]), "Failed to enable timer!");
430-
// start the timer
431-
CHECK_ERR(mcpwm_timer_start_stop(params->timers[0], MCPWM_TIMER_START_NO_STOP), "Failed to start the timer!");
432-
433423
_delay(1);
434424
SIMPLEFOC_ESP32_DEBUG("MCPWM configured!");
435425
// save the configuration variables for later
@@ -439,9 +429,19 @@ void* _configurePinsMCPWM(long pwm_frequency, int mcpwm_group, int timer_no, int
439429
}
440430

441431
// function setting the duty cycle to the MCPWM pin
442-
void _setDutyCycle(mcpwm_cmpr_handle_t cmpr, uint32_t mcpwm_period, float duty_cycle){
443-
float duty = constrain(duty_cycle, 0.0, 1.0);
444-
mcpwm_comparator_set_compare_value(cmpr, (uint32_t)(mcpwm_period*duty));
432+
bool _enableTimer(mcpwm_timer_handle_t timer){
433+
int ret = mcpwm_timer_enable(timer); // enable the timer
434+
if (ret == ESP_ERR_INVALID_STATE){ // if already enabled
435+
SIMPLEFOC_ESP32_DEBUG("Timer already enabled: "+String(i));
436+
}else if(ret != ESP_OK){
437+
SIMPLEFOC_ESP32_DEBUG("Failed to enable timer!"); // if failed
438+
return false;
439+
}
440+
if(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP)!=ESP_OK){
441+
SIMPLEFOC_ESP32_DEBUG("Failed to start the timer!");
442+
return false;
443+
}
445444
}
446445

446+
447447
#endif

src/drivers/hardware_specific/esp32/esp32_driver_mcpwm.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,5 +143,13 @@ void* _configurePinsMCPWM(long pwm_frequency, int mcpwm_group, int timer_no, int
143143
*/
144144
void _setDutyCycle(mcpwm_cmpr_handle_t cmpr, uint32_t mcpwm_period, float duty_cycle);
145145

146+
/**
147+
* Function checking if timer is enabled
148+
* @param timer - mcpwm timer handle
149+
*
150+
* @returns true if timer is enabled, false otherwise
151+
*/
152+
bool _enableTimer(mcpwm_timer_handle_t timer);
153+
146154
#endif
147155
#endif

src/drivers/hardware_specific/esp32/esp32_mcu.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,4 +218,17 @@ void _writeDutyCycle6PWM(float dc_a, float dc_b, float dc_c, PhaseState *phase_
218218
_setDutyCycle(((ESP32MCPWMDriverParams*)params)->comparator[5], period, (phase_state[2] == PHASE_ON || phase_state[2] == PHASE_LO) ? dc_c+dead_zone : 1.0f);
219219
#endif
220220
}
221+
222+
void* _enablePWM(void* params){
223+
SIMPLEFOC_ESP32_DEBUG("Enabling timers.");
224+
ESP32MCPWMDriverParams* p = (ESP32MCPWMDriverParams*)params;
225+
for (int i=0; i<2; i++){
226+
if (p->timers[i] == nullptr) continue; // if only one timer
227+
if(!_enableTimer(p->timers[i])){
228+
return SIMPLEFOC_DRIVER_INIT_FAILED;
229+
}
230+
}
231+
return params;
232+
}
233+
221234
#endif

src/drivers/hardware_specific/generic_mcu.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,10 @@ __attribute__((weak)) void _writeDutyCycle6PWM(float dc_a, float dc_b, float dc
122122
_UNUSED(dc_c);
123123
_UNUSED(phase_state);
124124
_UNUSED(params);
125+
}
126+
127+
// function enabling the power stage
128+
// - hardware specific
129+
__attribute__((weak)) void* _enablePWM(void* params){
130+
return params;
125131
}

0 commit comments

Comments
 (0)