From a7ed4ba247782915dd5ccbeb8d8258a2fb8e3951 Mon Sep 17 00:00:00 2001 From: askuric Date: Sat, 15 Jun 2024 17:49:38 +0200 Subject: [PATCH] an initial implementation of the lowside and inline current sense with the new esp32 api --- .../esp32/esp32_adc_driver.cpp | 2 +- .../esp32/esp32_adc_driver.h | 2 +- .../hardware_specific/esp32/esp32_mcu.cpp | 162 +++++++----------- .../esp32/esp32s_adc_driver.cpp | 2 +- src/drivers/BLDCDriver3PWM.cpp | 2 + src/drivers/BLDCDriver6PWM.cpp | 2 + src/drivers/StepperDriver2PWM.cpp | 2 + src/drivers/StepperDriver4PWM.cpp | 2 + src/drivers/hardware_api.h | 11 ++ .../esp32/esp32_driver_mcpwm.cpp | 26 +-- .../esp32/esp32_driver_mcpwm.h | 8 + .../hardware_specific/esp32/esp32_mcu.cpp | 13 ++ src/drivers/hardware_specific/generic_mcu.cpp | 6 + 13 files changed, 128 insertions(+), 112 deletions(-) diff --git a/src/current_sense/hardware_specific/esp32/esp32_adc_driver.cpp b/src/current_sense/hardware_specific/esp32/esp32_adc_driver.cpp index 4a37ddb8..7f0cc310 100644 --- a/src/current_sense/hardware_specific/esp32/esp32_adc_driver.cpp +++ b/src/current_sense/hardware_specific/esp32/esp32_adc_driver.cpp @@ -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" diff --git a/src/current_sense/hardware_specific/esp32/esp32_adc_driver.h b/src/current_sense/hardware_specific/esp32/esp32_adc_driver.h index 357b35b0..c79afdb4 100644 --- a/src/current_sense/hardware_specific/esp32/esp32_adc_driver.h +++ b/src/current_sense/hardware_specific/esp32/esp32_adc_driver.h @@ -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 * */ diff --git a/src/current_sense/hardware_specific/esp32/esp32_mcu.cpp b/src/current_sense/hardware_specific/esp32/esp32_mcu.cpp index d334008e..f3131a1e 100644 --- a/src/current_sense/hardware_specific/esp32/esp32_mcu.cpp +++ b/src/current_sense/hardware_specific/esp32/esp32_mcu.cpp @@ -2,26 +2,26 @@ #include "../../../drivers/hardware_api.h" #include "../../../drivers/hardware_specific/esp32/esp32_driver_mcpwm.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) -#include "esp32_adc_driver.h" - -#include "driver/mcpwm.h" +#include "driver/mcpwm_prelude.h" #include "soc/mcpwm_reg.h" #include "soc/mcpwm_struct.h" - #include #include #define _ADC_VOLTAGE 3.3f #define _ADC_RESOLUTION 4095.0f +// set the pin 19 in high during the adc interrupt +// #define SIMPLEFOC_ESP32_INTERRUPT_DEBUG typedef struct ESP32MCPWMCurrentSenseParams { int pins[3]; float adc_voltage_conv; - mcpwm_unit_t mcpwm_unit; - int buffer_index; + int adc_buffer[3] = {}; + int buffer_index = 0; + int no_adc_channels = 0; } ESP32MCPWMCurrentSenseParams; @@ -36,8 +36,8 @@ float _readADCVoltageInline(const int pinA, const void* cs_params){ // 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){ - _UNUSED(driver_params); + SIMPLEFOC_DEBUG("ESP32-CS: Configuring ADC inline"); if( _isset(pinA) ) pinMode(pinA, INPUT); if( _isset(pinB) ) pinMode(pinB, INPUT); if( _isset(pinC) ) pinMode(pinC, INPUT); @@ -51,30 +51,15 @@ void* _configureADCInline(const void* driver_params, const int pinA, const int p } - -/** - * Low side adc reading implementation -*/ - -static void IRAM_ATTR mcpwm0_isr_handler(void*); -static void IRAM_ATTR mcpwm1_isr_handler(void*); -byte currentState = 1; -// two mcpwm units -// - max 2 motors per mcpwm unit (6 adc channels) -int adc_pins[2][6]={0}; -int adc_pin_count[2]={0}; -uint32_t adc_buffer[2][6]={0}; -int adc_read_index[2]={0}; - // function reading an ADC value and returning the read voltage float _readADCVoltageLowSide(const int pin, const void* cs_params){ - mcpwm_unit_t unit = ((ESP32MCPWMCurrentSenseParams*)cs_params)->mcpwm_unit; - int buffer_index = ((ESP32MCPWMCurrentSenseParams*)cs_params)->buffer_index; - float adc_voltage_conv = ((ESP32MCPWMCurrentSenseParams*)cs_params)->adc_voltage_conv; - - for(int i=0; i < adc_pin_count[unit]; i++){ - if( pin == ((ESP32MCPWMCurrentSenseParams*)cs_params)->pins[i]) // found in the buffer - return adc_buffer[unit][buffer_index + i] * adc_voltage_conv; + 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; @@ -83,83 +68,68 @@ float _readADCVoltageLowSide(const int pin, const void* cs_params){ // function configuring low-side current sensing void* _configureADCLowSide(const void* driver_params, const int pinA,const int pinB,const int pinC){ - mcpwm_unit_t unit = ((ESP32MCPWMDriverParams*)driver_params)->mcpwm_unit; - int index_start = adc_pin_count[unit]; - if( _isset(pinA) ) adc_pins[unit][adc_pin_count[unit]++] = pinA; - if( _isset(pinB) ) adc_pins[unit][adc_pin_count[unit]++] = pinB; - if( _isset(pinC) ) adc_pins[unit][adc_pin_count[unit]++] = pinC; + SIMPLEFOC_DEBUG("ESP32-CS: Configuring ADC low-side"); + // 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; + if(mcpwm_timer_start_stop(p->timers[0], MCPWM_TIMER_START_NO_STOP) != ESP_ERR_INVALID_STATE){ + // if we get the invalid state error it means that the timer is not enabled + // that means that we can configure it for low-side current sensing + SIMPLEFOC_DEBUG("ESP32-CS: ERR - The timer is already enabled. Cannot be configured for low-side current sensing."); + return SIMPLEFOC_CURRENT_SENSE_INIT_FAILED; + } - 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), - .mcpwm_unit = unit, - .buffer_index = index_start - }; + 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; + } + 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){ - - mcpwm_dev_t* mcpwm_dev = ((ESP32MCPWMDriverParams*)driver_params)->mcpwm_dev; - mcpwm_unit_t mcpwm_unit = ((ESP32MCPWMDriverParams*)driver_params)->mcpwm_unit; - - // low-side register enable interrupt - mcpwm_dev->int_ena.timer0_tep_int_ena = true;//A PWM timer 0 TEP event will trigger this interrupt - // high side registers enable interrupt - //mcpwm_dev->int_ena.timer0_tep_int_ena = true;//A PWM timer 0 TEZ event will trigger this interrupt - - // register interrupts (mcpwm number, interrupt handler, handler argument = NULL, interrupt signal/flag, return handler = NULL) - if(mcpwm_unit == MCPWM_UNIT_0) - mcpwm_isr_register(mcpwm_unit, mcpwm0_isr_handler, NULL, ESP_INTR_FLAG_IRAM, NULL); //Set ISR Handler - else - mcpwm_isr_register(mcpwm_unit, mcpwm1_isr_handler, NULL, ESP_INTR_FLAG_IRAM, NULL); //Set ISR Handler -} - -static void IRAM_ATTR mcpwm0_isr_handler(void*) __attribute__ ((unused)); - -// Read currents when interrupt is triggered -static void IRAM_ATTR mcpwm0_isr_handler(void*){ - // // high side - // uint32_t mcpwm_intr_status = MCPWM0.int_st.timer0_tez_int_st; +#ifdef SIMPLEFOC_ESP32_INTERRUPT_DEBUG + pinMode(19, OUTPUT); +#endif + ESP32MCPWMDriverParams *p = (ESP32MCPWMDriverParams*)driver_params; - // low side - uint32_t mcpwm_intr_status = MCPWM0.int_st.timer0_tep_int_st; - if(mcpwm_intr_status){ - adc_buffer[0][adc_read_index[0]] = adcRead(adc_pins[0][adc_read_index[0]]); - adc_read_index[0]++; - if(adc_read_index[0] == adc_pin_count[0]) adc_read_index[0] = 0; - } - // low side - MCPWM0.int_clr.timer0_tep_int_clr = mcpwm_intr_status; - // high side - // MCPWM0.int_clr.timer0_tez_int_clr = mcpwm_intr_status_0; + mcpwm_timer_event_callbacks_t cbs_timer = { + .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 + digitalWrite(19, HIGH); + #endif + // increment buffer index + p->buffer_index = (p->buffer_index + 1) % p->no_adc_channels; + // sample the phase currents one at a time + p->adc_buffer[p->buffer_index] = adcRead(p->pins[p->buffer_index]); + #ifdef SIMPLEFOC_ESP32_INTERRUPT_DEBUG + digitalWrite(19, LOW); + #endif + return true; + } + }; + if(mcpwm_timer_register_event_callbacks(p->timers[0], &cbs_timer, cs_params) != ESP_OK){ + SIMPLEFOC_DEBUG("ESP32-CS: ERR - Failed to sync ADC and driver"); + } } -static void IRAM_ATTR mcpwm1_isr_handler(void*) __attribute__ ((unused)); - -// Read currents when interrupt is triggered -static void IRAM_ATTR mcpwm1_isr_handler(void*){ - // // high side - // uint32_t mcpwm_intr_status = MCPWM1.int_st.timer0_tez_int_st; - - // low side - uint32_t mcpwm_intr_status = MCPWM1.int_st.timer0_tep_int_st; - if(mcpwm_intr_status){ - adc_buffer[1][adc_read_index[1]] = adcRead(adc_pins[1][adc_read_index[1]]); - adc_read_index[1]++; - if(adc_read_index[1] == adc_pin_count[1]) adc_read_index[1] = 0; - } - // low side - MCPWM1.int_clr.timer0_tep_int_clr = mcpwm_intr_status; - // high side - // MCPWM1.int_clr.timer0_tez_int_clr = mcpwm_intr_status_0; -} #endif diff --git a/src/current_sense/hardware_specific/esp32/esp32s_adc_driver.cpp b/src/current_sense/hardware_specific/esp32/esp32s_adc_driver.cpp index 31cbb027..11149b4a 100644 --- a/src/current_sense/hardware_specific/esp32/esp32s_adc_driver.cpp +++ b/src/current_sense/hardware_specific/esp32/esp32s_adc_driver.cpp @@ -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" diff --git a/src/drivers/BLDCDriver3PWM.cpp b/src/drivers/BLDCDriver3PWM.cpp index 637c8db5..f08c9f11 100644 --- a/src/drivers/BLDCDriver3PWM.cpp +++ b/src/drivers/BLDCDriver3PWM.cpp @@ -20,6 +20,8 @@ BLDCDriver3PWM::BLDCDriver3PWM(int phA, int phB, int phC, int en1, int en2, int // enable motor driver void BLDCDriver3PWM::enable(){ + // enable hardware if available + _enablePWM(params); // enable_pin the driver - if enable_pin pin available if ( _isset(enableA_pin) ) digitalWrite(enableA_pin, enable_active_high); if ( _isset(enableB_pin) ) digitalWrite(enableB_pin, enable_active_high); diff --git a/src/drivers/BLDCDriver6PWM.cpp b/src/drivers/BLDCDriver6PWM.cpp index 4981858f..ba19becf 100644 --- a/src/drivers/BLDCDriver6PWM.cpp +++ b/src/drivers/BLDCDriver6PWM.cpp @@ -24,6 +24,8 @@ BLDCDriver6PWM::BLDCDriver6PWM(int phA_h,int phA_l,int phB_h,int phB_l,int phC_h // enable motor driver void BLDCDriver6PWM::enable(){ + // enable hardware if available + _enablePWM(params); // enable_pin the driver - if enable_pin pin available if ( _isset(enable_pin) ) digitalWrite(enable_pin, enable_active_high); // set phase state enabled diff --git a/src/drivers/StepperDriver2PWM.cpp b/src/drivers/StepperDriver2PWM.cpp index dbbf5b8f..e5f1930c 100644 --- a/src/drivers/StepperDriver2PWM.cpp +++ b/src/drivers/StepperDriver2PWM.cpp @@ -43,6 +43,8 @@ StepperDriver2PWM::StepperDriver2PWM(int _pwm1, int _dir1, int _pwm2, int _dir2, // enable motor driver void StepperDriver2PWM::enable(){ + // enable hardware if available + _enablePWM(params); // enable_pin the driver - if enable_pin pin available if ( _isset(enable_pin1) ) digitalWrite(enable_pin1, HIGH); if ( _isset(enable_pin2) ) digitalWrite(enable_pin2, HIGH); diff --git a/src/drivers/StepperDriver4PWM.cpp b/src/drivers/StepperDriver4PWM.cpp index 836f5472..f584a5b9 100644 --- a/src/drivers/StepperDriver4PWM.cpp +++ b/src/drivers/StepperDriver4PWM.cpp @@ -20,6 +20,8 @@ StepperDriver4PWM::StepperDriver4PWM(int ph1A,int ph1B,int ph2A,int ph2B,int en1 // enable motor driver void StepperDriver4PWM::enable(){ + // enable hardware if available + _enablePWM(params); // enable_pin the driver - if enable_pin pin available if ( _isset(enable_pin1) ) digitalWrite(enable_pin1, HIGH); if ( _isset(enable_pin2) ) digitalWrite(enable_pin2, HIGH); diff --git a/src/drivers/hardware_api.h b/src/drivers/hardware_api.h index 7809233d..07abb21e 100644 --- a/src/drivers/hardware_api.h +++ b/src/drivers/hardware_api.h @@ -27,6 +27,7 @@ // flag returned if driver init fails #define SIMPLEFOC_DRIVER_INIT_FAILED ((void*)-1) +#define SIMPLEFOC_DRIVER_INIT_SUCCESS ((void*)1) // generic implementation of the hardware specific structure // 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 */ void _writeDutyCycle6PWM(float dc_a, float dc_b, float dc_c, PhaseState *phase_state, void* params); +/** + * Function enabling the PWM outputs + * - hardware specific + * + * @param params the driver parameters + * + * @return the pointer to the driver parameters if successful, -1 if failed + */ +void* _enablePWM(void* params); + #endif \ No newline at end of file diff --git a/src/drivers/hardware_specific/esp32/esp32_driver_mcpwm.cpp b/src/drivers/hardware_specific/esp32/esp32_driver_mcpwm.cpp index 87f78788..1686bc0c 100644 --- a/src/drivers/hardware_specific/esp32/esp32_driver_mcpwm.cpp +++ b/src/drivers/hardware_specific/esp32/esp32_driver_mcpwm.cpp @@ -320,10 +320,6 @@ void* _configure6PWMPinsMCPWM(long pwm_frequency, int mcpwm_group, int timer_no, _configureCenterAlign(params->generator[2*i+1],params->comparator[2*i+1], SIMPLEFOC_PWM_LOWSIDE_ACTIVE_HIGH); } #endif - SIMPLEFOC_ESP32_DEBUG("Enabling the timer: "+String(timer_no)); - // Enable and start timer - CHECK_ERR(mcpwm_timer_enable(params->timers[0]), "Failed to enable timer!"); - CHECK_ERR(mcpwm_timer_start_stop(params->timers[0], MCPWM_TIMER_START_NO_STOP), "Failed to start the timer!"); _delay(1); SIMPLEFOC_ESP32_DEBUG("MCPWM configured!"); @@ -424,12 +420,6 @@ void* _configurePinsMCPWM(long pwm_frequency, int mcpwm_group, int timer_no, int _configureCenterAlign(params->generator[i],params->comparator[i], !SIMPLEFOC_PWM_ACTIVE_HIGH); } - SIMPLEFOC_ESP32_DEBUG("Enabling the timer: "+String(timer_no)); - // Enable and start timer if not shared - if (!shared_timer) CHECK_ERR(mcpwm_timer_enable(params->timers[0]), "Failed to enable timer!"); - // start the timer - CHECK_ERR(mcpwm_timer_start_stop(params->timers[0], MCPWM_TIMER_START_NO_STOP), "Failed to start the timer!"); - _delay(1); SIMPLEFOC_ESP32_DEBUG("MCPWM configured!"); // save the configuration variables for later @@ -439,9 +429,19 @@ void* _configurePinsMCPWM(long pwm_frequency, int mcpwm_group, int timer_no, int } // function setting the duty cycle to the MCPWM pin -void _setDutyCycle(mcpwm_cmpr_handle_t cmpr, uint32_t mcpwm_period, float duty_cycle){ - float duty = constrain(duty_cycle, 0.0, 1.0); - mcpwm_comparator_set_compare_value(cmpr, (uint32_t)(mcpwm_period*duty)); +bool _enableTimer(mcpwm_timer_handle_t timer){ + int ret = mcpwm_timer_enable(timer); // enable the timer + if (ret == ESP_ERR_INVALID_STATE){ // if already enabled + SIMPLEFOC_ESP32_DEBUG("Timer already enabled: "+String(i)); + }else if(ret != ESP_OK){ + SIMPLEFOC_ESP32_DEBUG("Failed to enable timer!"); // if failed + return false; + } + if(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP)!=ESP_OK){ + SIMPLEFOC_ESP32_DEBUG("Failed to start the timer!"); + return false; + } } + #endif \ No newline at end of file diff --git a/src/drivers/hardware_specific/esp32/esp32_driver_mcpwm.h b/src/drivers/hardware_specific/esp32/esp32_driver_mcpwm.h index d0b7933e..4aa4f45e 100644 --- a/src/drivers/hardware_specific/esp32/esp32_driver_mcpwm.h +++ b/src/drivers/hardware_specific/esp32/esp32_driver_mcpwm.h @@ -143,5 +143,13 @@ void* _configurePinsMCPWM(long pwm_frequency, int mcpwm_group, int timer_no, int */ void _setDutyCycle(mcpwm_cmpr_handle_t cmpr, uint32_t mcpwm_period, float duty_cycle); +/** + * Function checking if timer is enabled + * @param timer - mcpwm timer handle + * + * @returns true if timer is enabled, false otherwise + */ +bool _enableTimer(mcpwm_timer_handle_t timer); + #endif #endif \ No newline at end of file diff --git a/src/drivers/hardware_specific/esp32/esp32_mcu.cpp b/src/drivers/hardware_specific/esp32/esp32_mcu.cpp index 33f9db20..bc1990f4 100644 --- a/src/drivers/hardware_specific/esp32/esp32_mcu.cpp +++ b/src/drivers/hardware_specific/esp32/esp32_mcu.cpp @@ -218,4 +218,17 @@ void _writeDutyCycle6PWM(float dc_a, float dc_b, float dc_c, PhaseState *phase_ _setDutyCycle(((ESP32MCPWMDriverParams*)params)->comparator[5], period, (phase_state[2] == PHASE_ON || phase_state[2] == PHASE_LO) ? dc_c+dead_zone : 1.0f); #endif } + +void* _enablePWM(void* params){ + SIMPLEFOC_ESP32_DEBUG("Enabling timers."); + ESP32MCPWMDriverParams* p = (ESP32MCPWMDriverParams*)params; + for (int i=0; i<2; i++){ + if (p->timers[i] == nullptr) continue; // if only one timer + if(!_enableTimer(p->timers[i])){ + return SIMPLEFOC_DRIVER_INIT_FAILED; + } + } + return params; +} + #endif diff --git a/src/drivers/hardware_specific/generic_mcu.cpp b/src/drivers/hardware_specific/generic_mcu.cpp index b6bc2f06..3d648d29 100644 --- a/src/drivers/hardware_specific/generic_mcu.cpp +++ b/src/drivers/hardware_specific/generic_mcu.cpp @@ -122,4 +122,10 @@ __attribute__((weak)) void _writeDutyCycle6PWM(float dc_a, float dc_b, float dc _UNUSED(dc_c); _UNUSED(phase_state); _UNUSED(params); +} + +// function enabling the power stage +// - hardware specific +__attribute__((weak)) void* _enablePWM(void* params){ + return params; } \ No newline at end of file