From b03aef88a1f2f77a38d9f1e8d76434b58b14f55a Mon Sep 17 00:00:00 2001 From: Nicholas DePatie <80368116+nwdepatie@users.noreply.github.com> Date: Tue, 12 Mar 2024 13:32:38 -0400 Subject: [PATCH] #8 gatedriver pwm (#31) * Added some pulse-setting functionality * Fixed signature and variable name typos * Switched to float array duty cycle parameter * Fixed signature and removed TODOs * Moved PWM config to gatedrive struct * Added mutex for timer * Fixed typo --------- Co-authored-by: Ethan Parab <59212466+MandarinPine18@users.noreply.github.com> --- CM7/Core/Inc/gatedriver.h | 11 ++-- CM7/Core/Src/gatedriver.c | 119 ++++++++++++++++++++++++++++---------- 2 files changed, 96 insertions(+), 34 deletions(-) diff --git a/CM7/Core/Inc/gatedriver.h b/CM7/Core/Inc/gatedriver.h index cb7867f..48508ea 100644 --- a/CM7/Core/Inc/gatedriver.h +++ b/CM7/Core/Inc/gatedriver.h @@ -13,10 +13,13 @@ enum phase{ }; typedef struct { - I2C_HandleTypeDef* hi2c; + TIM_HandleTypeDef* tim; + osMutexId_t* tim_mutex; + TIM_OC_InitTypeDef* pPWMConfig; + uint32_t pulses[]; } gatedriver_t; -gatedriver_t* gatedrv_init(/*TODO: Pass hardware interfaces*/); +gatedriver_t* gatedrv_init(TIM_HandleTypeDef* tim); int16_t gatedrv_read_dc_voltage(gatedriver_t* drv); @@ -24,8 +27,8 @@ int16_t gatedrv_read_dc_current(gatedriver_t* drv); /* Note: This has to atomically write to ALL PWM registers */ //TODO: mechanism for PWM synchronization -int16_t gatedrv_write_pwm(gatedriver_t* drv); +int16_t gatedrv_write_pwm(gatedriver_t* drv, float duty_cycles[]); int16_t gatedrv_read_igbt_temp(gatedriver_t* drv); -#endif /* GATEDRIVER_H */ \ No newline at end of file +#endif /* GATEDRIVER_H */ diff --git a/CM7/Core/Src/gatedriver.c b/CM7/Core/Src/gatedriver.c index d645c76..a5647ff 100644 --- a/CM7/Core/Src/gatedriver.c +++ b/CM7/Core/Src/gatedriver.c @@ -5,6 +5,10 @@ #include #include +#define PERIOD_VALUE (uint32_t)(2000 - 1) + +const static osMutexAttr_t gatedrv_tim_mutex_attr; + //TODO: Look up STM callback func pointer for ADCs static void gatedrv_current_adc_cb(gatedriver_t* drv) { @@ -31,41 +35,43 @@ static void gatedrv_fault_cb(gatedriver_t* drv) } -gatedriver_t* gatedrv_init() +gatedriver_t* gatedrv_init(TIM_HandleTypeDef* tim) { - //TODO: Assert hardware params - //assert(hi2c); - //assert(accel_adc1); - //assert(accel_adc2); - //assert(brake_adc); - //assert(led_gpio); - //assert(watchdog_gpio); + /* Assert hardware params */ + assert(tim); /* Create MPU struct */ gatedriver_t* gatedriver = malloc(sizeof(gatedriver_t)); assert(gatedriver); - //TODO: Set interfaces - //mpu->hi2c = hi2c; - //mpu->accel_adc1 = accel_adc1; - //mpu->accel_adc2 = accel_adc2; - //mpu->brake_adc = brake_adc; - //mpu->led_gpio = led_gpio; - //mpu->watchdog_gpio = watchdog_gpio; - - //TODO: Init hardware - /* Initialize the Onboard Temperature Sensor */ - //mpu->temp_sensor = malloc(sizeof(sht30_t)); - //assert(mpu->temp_sensor); - //mpu->temp_sensor->i2c_handle = hi2c; - //assert(!sht30_init(mpu->temp_sensor)); /* This is always connected */ - - //TODO: Init Mutexes + /* Set interfaces */ + gatedriver->tim = tim; + + /* Init hardware */ + tim->Init.Prescaler = 0; + tim->Init.Period = PERIOD_VALUE; + tim->Init.ClockDivision = 0; + tim->Init.CounterMode = TIM_COUNTERMODE_UP; + tim->Init.RepetitionCounter = 0; + if(HAL_TIM_PWM_Init(tim) != HAL_OK) { + // TODO: how to handle this error? + } + + /* Common configuration for all PWM channels */ + TIM_OC_InitTypeDef PWMConfig; + PWMConfig.OCMode = TIM_OCMODE_PWM1; + PWMConfig.OCPolarity = TIM_OCPOLARITY_HIGH; + PWMConfig.OCNPolarity = TIM_OCNPOLARITY_HIGH; + PWMConfig.OCIdleState = TIM_OCIDLESTATE_SET; + PWMConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET; + PWMConfig.OCFastMode = TIM_OCFAST_DISABLE; + gatedriver->pPWMConfig = &PWMConfig; + /* Create Mutexes */ - //mpu->i2c_mutex = osMutexNew(&mpu_i2c_mutex_attr); - //assert(mpu->i2c_mutex); + gatedriver->tim_mutex = osMutexNew(&gatedrv_tim_mutex_attr); + assert(gatedriver->tim_mutex); - //TODO: Link interrupts to callbacks + //TODO: Link interrupts to callbacks return gatedriver; } @@ -81,10 +87,63 @@ int16_t gatedrv_read_dc_current(gatedriver_t* drv) } /* Note: This has to atomically write to ALL PWM registers */ -//TODO: mechanism for PWM synchronization -int16_t gatedrv_write_pwm(gatedriver_t* drv) +int16_t gatedrv_write_pwm(gatedriver_t* drv, float duty_cycles[]) { - + /* Acquiring mutex lock */ + osStatus_t mut_stat = osMutexAcquire(drv->tim_mutex, osWaitForever); + if (mut_stat) { + return mut_stat; + } + + /* Computing pulses */ + uint32_t pulses[3]; + pulses[0] = (uint32_t) (duty_cycles[0] * PERIOD_VALUE / 100); + pulses[1] = (uint32_t) (duty_cycles[1] * PERIOD_VALUE / 100); + pulses[2] = (uint32_t) (duty_cycles[2] * PERIOD_VALUE / 100); + + /* Getting PWM channel config */ + TIM_OC_InitTypeDef* config = drv->pPWMConfig; + + /* Attempting to set channel 1 */ + config->Pulse = pulses[0]; + if(HAL_TIM_PWM_ConfigChannel(drv->tim, config, TIM_CHANNEL_1) != HAL_OK) + { + /* Do nothing and return */ + return 1; + } + + /* Attempting to set channel 2 */ + config->Pulse = pulses[1]; + if(HAL_TIM_PWM_ConfigChannel(drv->tim, config, TIM_CHANNEL_2) != HAL_OK) + { + /* Attempt to revert last channel change and return */ + config->Pulse = drv->pulses[0]; + HAL_TIM_PWM_ConfigChannel(drv->tim, config, TIM_CHANNEL_1); + + return 1; + } + + /* Attempting to set channel 3 */ + config->Pulse = pulses[2]; + if(HAL_TIM_PWM_ConfigChannel(drv->tim, config, TIM_CHANNEL_3) != HAL_OK) + { + /* Attempt to revert previous channel changes and return */ + config->Pulse = drv->pulses[0]; + HAL_TIM_PWM_ConfigChannel(drv->tim, config, TIM_CHANNEL_1); + + config->Pulse = drv->pulses[1]; + HAL_TIM_PWM_ConfigChannel(drv->tim, config, TIM_CHANNEL_2); + + return 1; + } + + /* Successful PWM modifications - save configuration, release mutex, and return */ + drv->pulses[0] = pulses[0]; + drv->pulses[1] = pulses[1]; + drv->pulses[2] = pulses[2]; + + osMutexRelease(drv->tim_mutex); + return 0; } int16_t gatedrv_read_igbt_temp(gatedriver_t* drv)