#include "pwm.h" //#include "rng.h" PWM_HandleTypeDef hpwm1; PWM_SlaveHandleTypeDef hpwm2; PWM_SlaveHandleTypeDef hpwm3; uint32_t sin_table[SIN_TABLE_SIZE_MAX]; unsigned ActiveChannelSHDW_Master; float DeadTimeCnt_Master; unsigned ActiveChannelSHDW_Slave2; float DeadTimeCnt_Slave2; float shiftPHASE1 = 0.6666666666; float shiftPHASE2 = 0.3333333333; unsigned ActiveChannelSHDW_Slave3; float DeadTimeCnt_Slave3; /** * @brief First set up of PWM. * @note Первый инит ШИМ. Заполняет структуры и инициализирует таймер для генерации синуоидального ШИМ. * Скважность ШИМ меняется по закону синусоиды, каждый канал генерирует свой полупериод синуса (от -1 до 0 И от 0 до 1) * ШИМ генерируется на одном канале. * @note This called from main */ void PWM_Sine_FirstInit(void) { hpwm1.sPWM_Config.PWM_Mode = (PWM_ModeCoilsTypeDef*)&coils_regs[0]; hpwm1.sPWM_Config.PWM_Settings = (PWM_ModeRegsTypeDef*)&pwm_ctrl[0]; // PWM RAMP INIT hpwm1.pDuty_Table_Origin = SIN_TABLE_ORIGIN; hpwm1.hramp.Kp = 0; hpwm1.hramp.Ki = PWM_RAMP_SPEED; hpwm1.hramp.Kd = 0; hpwm1.hramp.limMax = 656; hpwm1.hramp.limMin = 0; hpwm1.hramp.limMaxInt = 20; hpwm1.hramp.limMinInt = -20; hpwm1.hramp.SampleT = (1.0f / HZ_TIMER_CTRL); // PWM CONTROL PINS INIT GPIO_InitTypeDef GPIO_InitStruct = { 0 }; GPIO_Clock_Enable(GPIOC); GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); GPIOC->ODR |= 1 << 0;//подача 0 разрешает . Аппаратное разрешение и запрет не подачу шим . Cигнал идет на логический элемент & 74AC08d GPIO_InitStruct.Pin = GPIO_PIN_1; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); //кнопка для вкл аппаратно шим 74AC08d //---------PWM TIMER1 INIT------------ // channels settings hpwm1.sConfigOC.OCMode = TIM_OCMODE_PWM1; hpwm1.sConfigOC.Pulse = 0; hpwm1.sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW; //hpwm1.sConfigOC.OCNPolarity=TIM_OCNPOLARITY_LOW; hpwm1.sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; // tim1 settings hpwm1.stim.htim.Instance = TIMER_PWM1_INSTANCE; hpwm1.stim.sTimMode = TIM_IT_MODE; hpwm1.stim.sTimFreqHz = HZ_TIMER_PWM; hpwm1.stim.sTickBaseMHz = PROJSET.TIM_PWM_TICKBASE; hpwm1.stim.sTimAHBFreqMHz = PROJSET.TIM_PWM_AHB_FREQ; hpwm1.GPIOx = TIMER_PWM1_GPIOx; hpwm1.GPIO_PIN_X1 = PROJSET.TIM_PWM1_GPIO_PIN_X1; hpwm1.GPIO_PIN_X2 = PROJSET.TIM_PWM1_GPIO_PIN_X2; hpwm1.PWM_Channel1 = PROJSET.TIM_PWM1_TIM_CHANNEL1; hpwm1.PWM_Channel2 = PROJSET.TIM_PWM1_TIM_CHANNEL2; hpwm1.hpwm2 = (void*)&hpwm2; hpwm1.hpwm3 = (void*)&hpwm3; TIM_Base_Init(&hpwm1.stim); TIM_Output_PWM_Init(&hpwm1.stim.htim, &hpwm1.sConfigOC, hpwm1.PWM_Channel1, hpwm1.GPIOx, hpwm1.GPIO_PIN_X1); TIM_Output_PWM_Init(&hpwm1.stim.htim, &hpwm1.sConfigOC, hpwm1.PWM_Channel2, hpwm1.GPIOx, hpwm1.GPIO_PIN_X2); // PWM SLAVES INIT hpwm2.hMasterPWM = &hpwm1; hpwm2.stim = hpwm1.stim; hpwm2.stim.htim.Instance = (TIM_TypeDef*)PROJSET.TIM_PWM2_INSTANCE; hpwm2.GPIOx = (GPIO_TypeDef*)PROJSET.TIM_PWM2_GPIOx; hpwm2.GPIO_PIN_X1 = PROJSET.TIM_PWM2_GPIO_PIN_X1; hpwm2.GPIO_PIN_X2 = PROJSET.TIM_PWM2_GPIO_PIN_X2; hpwm2.PWM_Channel1 = PROJSET.TIM_PWM2_TIM_CHANNEL1; hpwm2.PWM_Channel2 = PROJSET.TIM_PWM2_TIM_CHANNEL2; //hpwm2.Duty_Shift_Ratio = shiftPHASE1; hpwm2.Duty_Shift_Ratio = shiftPHASE1; hpwm3.hMasterPWM = &hpwm1; hpwm3.stim = hpwm1.stim; hpwm3.stim.htim.Instance = (TIM_TypeDef*)PROJSET.TIM_PWM3_INSTANCE; hpwm3.GPIOx = (GPIO_TypeDef*)PROJSET.TIM_PWM3_GPIOx; hpwm3.GPIO_PIN_X1 = PROJSET.TIM_PWM3_GPIO_PIN_X1; hpwm3.GPIO_PIN_X2 = PROJSET.TIM_PWM3_GPIO_PIN_X2; hpwm3.PWM_Channel1 = PROJSET.TIM_PWM3_TIM_CHANNEL1; hpwm3.PWM_Channel2 = PROJSET.TIM_PWM3_TIM_CHANNEL2; //hpwm3.Duty_Shift_Ratio = shiftPHASE2; hpwm3.Duty_Shift_Ratio = shiftPHASE2; PWM_SlavePhase_Init(&hpwm2); PWM_SlavePhase_Init(&hpwm3); //----------TIMERS START------------- HAL_TIM_Base_Start_IT(&hpwm1.stim.htim); // timer for PWM HAL_TIM_PWM_Start(&hpwm1.stim.htim, hpwm1.PWM_Channel1); // PWM channel 1 HAL_TIM_PWM_Start(&hpwm1.stim.htim, hpwm1.PWM_Channel2); // PWM channel 2 } /** * @brief PWM Handler. * @param hpwm - указатель на хендл ШИМ. * @note Управляет скважностью ШИМ. * @note This called from TIM_PWM_Handler */ void PWM_Handler(PWM_HandleTypeDef* hpwm) { uint16_t rotate_ind_A; uint16_t rotate_ind_B; uint16_t rotate_ind_C; // rotate pwm rotate_ind_A = PWM_Get_Duty_Table_Ind(hpwm, hpwm->stim.sTimFreqHz); if (PWM_Get_Mode(hpwm, PWM_PHASE_MODE)) { rotate_ind_B = PWM_SlavePhase_Calc_TableInd(PWM_Set_pSlaveHandle(hpwm, hpwm2), rotate_ind_A); rotate_ind_C = PWM_SlavePhase_Calc_TableInd(PWM_Set_pSlaveHandle(hpwm, hpwm3), rotate_ind_A); } if (hpwm->PWM_Value == 0) // if value = 0 reset all channels { PWM_Set_Compare1(hpwm, 0); // reset first channel PWM_Set_Compare2(hpwm, 0); // reset second channel PWM_Set_Compare1(PWM_Set_pSlaveHandle(hpwm, hpwm2), 0); // reset first channel PWM_Set_Compare2(PWM_Set_pSlaveHandle(hpwm, hpwm2), 0); // reset second channel PWM_Set_Compare1(PWM_Set_pSlaveHandle(hpwm, hpwm3), 0); // reset first channel PWM_Set_Compare2(PWM_Set_pSlaveHandle(hpwm, hpwm3), 0); // reset second channel return; } //--------BRIDGE MODE DISABLE-------- if (PWM_Get_Mode(&hpwm1, PWM_BRIDGE_MODE) == 0) { //-----------PWM DC MODE------------- if (PWM_Get_Mode(&hpwm1, PWM_DC_MODE)) PWM_SingleChannel_Mode(hpwm, rotate_ind_A, 0); //------------SINUS MODE------------- else PWM_SingleChannel_Mode(hpwm, rotate_ind_A, 1); } //---------BRIDGE MODE ENABLE-------- else { if (PWM_Get_Mode(&hpwm1, PWM_DC_MODE)) //-----------PWM DC MODE------------- PWM_DC_Bridge_Mode(hpwm, rotate_ind_A, rotate_ind_B, rotate_ind_C); //------------SINUS MODE------------- else PWM_Sine_Bridge_Mode(hpwm, rotate_ind_A, rotate_ind_B, rotate_ind_C); } //-----CHECK CHANNELS FOR ERRORS----- uint16_t min_duty = PWM_Calc_Min_Duty(hpwm); uint16_t max_duty = PWM_Calc_Max_Duty(hpwm); // IF FIRST CHANNEL IS ACRIVE if (PWM_Get_Compare1(hpwm) != 0) { // Duty shoud be bigger or equeal than min duration if (PWM_Get_Compare1(hpwm) < min_duty) PWM_Set_Compare1(hpwm, min_duty); // Duty shoud be less or equeal than ARR-min duration if (PWM_Get_Compare1(hpwm) > max_duty) PWM_Set_Compare1(hpwm, max_duty); } // IF SECOND CHANNEL IS ACRIVE else if (PWM_Get_Compare2(hpwm) != 0) { // Duty shoud be bigger or equeal than min duration if (PWM_Get_Compare2(hpwm) < min_duty) PWM_Set_Compare2(hpwm, min_duty); // Duty shoud be less or equeal than ARR if (PWM_Get_Compare2(hpwm) > max_duty) PWM_Set_Compare2(hpwm, max_duty); } // IF BOTH CHANNEL IS ACRIVE if ((PWM_Get_Compare1(hpwm) != 0) && (PWM_Get_Compare2(hpwm) != 0)) { // Only one channel shoud be active so disable all PWM_Set_Compare1(hpwm, 0); PWM_Set_Compare2(hpwm, 0); } PWM_SlavePhase_Check_Channels(PWM_Set_pSlaveHandle(hpwm, hpwm2)); PWM_SlavePhase_Check_Channels(PWM_Set_pSlaveHandle(hpwm, hpwm3)); if (hpwm->PWM_DeadTime) { PWM_CreateDeadTime(hpwm, &DeadTimeCnt_Master, &ActiveChannelSHDW_Master); PWM_SlavePhase_CreateDeadTime(PWM_Set_pSlaveHandle(hpwm, hpwm2), &DeadTimeCnt_Slave2, &ActiveChannelSHDW_Slave2); PWM_SlavePhase_CreateDeadTime(PWM_Set_pSlaveHandle(hpwm, hpwm3), &DeadTimeCnt_Slave3, &ActiveChannelSHDW_Slave3); } } ///** // * @brief . // * @param hspwm - указатель на хендл слейв ШИМ. // * @param sin_ind - индекс таблицы для Мастер ШИМ. // * @note Индекс для свейл ШИМ расчитывается в самой функции. // */ //void PWM_Sine_SingleChannel_Mode(PWM_HandleTypeDef *hpwm, uint16_t rotate_ind_A, uint16_t rotate_ind_B, uint16_t rotate_ind_C) //{ // //----------MASTER PWM----------- // PWM_Set_Duty_From_Table(hpwm, rotate_ind_A); // set phase 1 (A) // // //----------SLAVE PWMs----------- // if (PWM_Get_Mode(hpwm, PWM_PHASE_MODE)) // { // PWM_SlaveHandleTypeDef *hspwm = PWM_Set_pSlaveHandle(hpwm,hpwm2); // PWM_Set_SlaveDuty_From_Table(hspwm, rotate_ind_B); // set phase 2 (B) // // hspwm = PWM_Set_pSlaveHandle(hpwm,hpwm3); // PWM_Set_SlaveDuty_From_Table(hspwm, rotate_ind_C); // set phase 3 (C) // } //} /** * @brief . * @param hspwm - указатель на хендл слейв ШИМ. * @param sin_ind - индекс таблицы для Мастер ШИМ. * @note Индекс для свейл ШИМ расчитывается в самой функции. */ void PWM_Sine_Bridge_Mode(PWM_HandleTypeDef* hpwm, uint16_t rotate_ind_A, uint16_t rotate_ind_B, uint16_t rotate_ind_C) { //----------MASTER PWM----------- // SET PHASE 1 (A) int Duty = PWM_Get_Table_Element_Signed(hpwm, rotate_ind_A); // если это первая полуволна if (Duty >= 0) { PWM_Set_Compare1(hpwm, Duty + PWM_Calc_Min_Duty(hpwm)); // set first channel PWM_Set_Compare2(hpwm, 0); // reset second channel } // если это вторая полуволна else { PWM_Set_Compare1(hpwm, 0); // reset first channel PWM_Set_Compare2(hpwm, (-Duty) + PWM_Calc_Min_Duty(hpwm)); // set second channel } //----------SLAVE PWMs----------- if (PWM_Get_Mode(hpwm, PWM_PHASE_MODE)) { // SET PHASE 2 (B) PWM_SlaveHandleTypeDef* hspwm = PWM_Set_pSlaveHandle(hpwm, hpwm2); Duty = PWM_Get_Table_Element_Signed(hpwm, rotate_ind_B); // если это первая полуволна if (Duty > 0) { PWM_Set_Compare1(hspwm, Duty + PWM_Calc_Min_Duty(hspwm->hMasterPWM)); // set first channel PWM_Set_Compare2(hspwm, 0); // reset second channel } // если это вторая полуволна else { PWM_Set_Compare1(hspwm, 0); // reset first channel PWM_Set_Compare2(hspwm, (-Duty) + PWM_Calc_Min_Duty(hspwm->hMasterPWM)); // set second channel } // SET PHASE 3 (C) hspwm = PWM_Set_pSlaveHandle(hpwm, hpwm3); Duty = PWM_Get_Table_Element_Signed(hpwm, rotate_ind_C); // если это первая полуволна if (Duty > 0) { PWM_Set_Compare1(hspwm, Duty + PWM_Calc_Min_Duty(hspwm->hMasterPWM)); // set first channel PWM_Set_Compare2(hspwm, 0); // reset second channel } // если это вторая полуволна else { PWM_Set_Compare1(hspwm, 0); // reset first channel PWM_Set_Compare2(hspwm, (-Duty) + PWM_Calc_Min_Duty(hspwm->hMasterPWM)); // set second channel } } else { PWM_Set_Compare1(PWM_Set_pSlaveHandle(hpwm, hpwm2), 0); // reset first channel PWM_Set_Compare2(PWM_Set_pSlaveHandle(hpwm, hpwm2), 0); // reset second channel PWM_Set_Compare1(PWM_Set_pSlaveHandle(hpwm, hpwm3), 0); // reset first channel PWM_Set_Compare2(PWM_Set_pSlaveHandle(hpwm, hpwm3), 0); // reset second channel } } /** * @brief . * @param hspwm - указатель на хендл слейв ШИМ. * @param sin_ind - индекс таблицы для Мастер ШИМ. * @note Индекс для свейл ШИМ расчитывается в самой функции. */ void PWM_SingleChannel_Mode(PWM_HandleTypeDef* hpwm, uint16_t rotate_ind_A, uint8_t SineOrDC) { PWM_SlaveHandleTypeDef* hspwm2 = PWM_Set_pSlaveHandle(hpwm, hpwm2); PWM_SlaveHandleTypeDef* hspwm3 = PWM_Set_pSlaveHandle(hpwm, hpwm3); // PWM_Set_Compare1(hpwm, 0); // reset first channel // PWM_Set_Compare2(hpwm, 0); // reset second channel // PWM_Set_Compare1(PWM_Set_pSlaveHandle(hpwm,hpwm2), 0); // reset first channel // PWM_Set_Compare2(PWM_Set_pSlaveHandle(hpwm,hpwm2), 0); // reset second channel // PWM_Set_Compare1(PWM_Set_pSlaveHandle(hpwm,hpwm3), 0); // reset first channel // PWM_Set_Compare2(PWM_Set_pSlaveHandle(hpwm,hpwm3), 0); // reset second channel switch (PWM_Get_Mode(hpwm, PWM_ACTIVECHANNEL_MODE)) { case PWM_ACTIVECHANNEL_A0: if (SineOrDC) PWM_Set_Duty_From_Table(hpwm, hpwm->PWM_Channel1, rotate_ind_A); else PWM_Set_Duty_From_Value(hpwm, hpwm->PWM_Channel1); // set first channel PWM_Set_Compare2(hpwm, 0); // reset second channel PWM_Set_Compare1(PWM_Set_pSlaveHandle(hpwm, hpwm2), 0); // reset first channel PWM_Set_Compare2(PWM_Set_pSlaveHandle(hpwm, hpwm2), 0); // reset second channel PWM_Set_Compare1(PWM_Set_pSlaveHandle(hpwm, hpwm3), 0); // reset first channel PWM_Set_Compare2(PWM_Set_pSlaveHandle(hpwm, hpwm3), 0); // reset second channel break; case PWM_ACTIVECHANNEL_A1: if (SineOrDC) PWM_Set_Duty_From_Table(hpwm, hpwm->PWM_Channel2, rotate_ind_A); else PWM_Set_Duty_From_Value(hpwm, hpwm->PWM_Channel2); // set second channel PWM_Set_Compare1(hpwm, 0); // reset first channel PWM_Set_Compare1(PWM_Set_pSlaveHandle(hpwm, hpwm2), 0); // reset first channel PWM_Set_Compare2(PWM_Set_pSlaveHandle(hpwm, hpwm2), 0); // reset second channel PWM_Set_Compare1(PWM_Set_pSlaveHandle(hpwm, hpwm3), 0); // reset first channel PWM_Set_Compare2(PWM_Set_pSlaveHandle(hpwm, hpwm3), 0); // reset second channel break; case PWM_ACTIVECHANNEL_B0: if (SineOrDC) PWM_Set_SlaveDuty_From_Table(hspwm2, hspwm2->PWM_Channel1, rotate_ind_A); else PWM_Set_SlaveDuty_From_Value(hspwm2, hspwm2->PWM_Channel1); // set first channel PWM_Set_Compare1(hpwm, 0); // reset first channel PWM_Set_Compare2(hpwm, 0); // reset second channel PWM_Set_Compare2(PWM_Set_pSlaveHandle(hpwm, hpwm2), 0); // reset second channel PWM_Set_Compare1(PWM_Set_pSlaveHandle(hpwm, hpwm3), 0); // reset first channel PWM_Set_Compare2(PWM_Set_pSlaveHandle(hpwm, hpwm3), 0); // reset second channel break; case PWM_ACTIVECHANNEL_B1: if (SineOrDC) PWM_Set_SlaveDuty_From_Table(hspwm2, hspwm2->PWM_Channel2, rotate_ind_A); else PWM_Set_SlaveDuty_From_Value(hspwm2, hspwm2->PWM_Channel2); // set second channel PWM_Set_Compare1(hpwm, 0); // reset first channel PWM_Set_Compare2(hpwm, 0); // reset second channel PWM_Set_Compare1(PWM_Set_pSlaveHandle(hpwm, hpwm2), 0); // reset first channel PWM_Set_Compare1(PWM_Set_pSlaveHandle(hpwm, hpwm3), 0); // reset first channel PWM_Set_Compare2(PWM_Set_pSlaveHandle(hpwm, hpwm3), 0); // reset second channel break; case PWM_ACTIVECHANNEL_C0: if (SineOrDC) PWM_Set_SlaveDuty_From_Table(hspwm3, hspwm3->PWM_Channel1, rotate_ind_A); else PWM_Set_SlaveDuty_From_Value(hspwm3, hspwm3->PWM_Channel1); // set first channel PWM_Set_Compare1(hpwm, 0); // reset first channel PWM_Set_Compare2(hpwm, 0); // reset second channel PWM_Set_Compare1(PWM_Set_pSlaveHandle(hpwm, hpwm2), 0); // reset first channel PWM_Set_Compare2(PWM_Set_pSlaveHandle(hpwm, hpwm2), 0); // reset second channel PWM_Set_Compare2(PWM_Set_pSlaveHandle(hpwm, hpwm3), 0); // reset second channel break; case PWM_ACTIVECHANNEL_C1: if (SineOrDC) PWM_Set_SlaveDuty_From_Table(hspwm3, hspwm3->PWM_Channel2, rotate_ind_A); else PWM_Set_SlaveDuty_From_Value(hspwm3, hspwm3->PWM_Channel2); // set second channel PWM_Set_Compare1(hpwm, 0); // reset first channel PWM_Set_Compare2(hpwm, 0); // reset second channel PWM_Set_Compare1(PWM_Set_pSlaveHandle(hpwm, hpwm2), 0); // reset first channel PWM_Set_Compare2(PWM_Set_pSlaveHandle(hpwm, hpwm2), 0); // reset second channel PWM_Set_Compare1(PWM_Set_pSlaveHandle(hpwm, hpwm3), 0); // reset first channel break; default: PWM_Set_Compare1(hpwm, 0); // reset first channel PWM_Set_Compare2(hpwm, 0); // reset second channel PWM_Set_Compare1(PWM_Set_pSlaveHandle(hpwm, hpwm2), 0); // reset first channel PWM_Set_Compare2(PWM_Set_pSlaveHandle(hpwm, hpwm2), 0); // reset second channel PWM_Set_Compare1(PWM_Set_pSlaveHandle(hpwm, hpwm3), 0); // reset first channel PWM_Set_Compare2(PWM_Set_pSlaveHandle(hpwm, hpwm3), 0); // reset second channel break; } } /** * @brief . * @param hspwm - указатель на хендл слейв ШИМ. * @param sin_ind - индекс таблицы для Мастер ШИМ. * @note Индекс для свейл ШИМ расчитывается в самой функции. */ void PWM_DC_Bridge_Mode(PWM_HandleTypeDef* hpwm, uint16_t rotate_ind_A, uint16_t rotate_ind_B, uint16_t rotate_ind_C) { //----------MASTER PWM----------- // SET PHASE 1 (A) int Duty = PWM_Get_Table_Element_Signed(hpwm, rotate_ind_A); // если это первая полуволна if (Duty >= 0) { PWM_Set_Duty_From_DutyBridge(hpwm, hpwm->PWM_Channel1); // set first channel PWM_Set_Compare2(hpwm, 0); // reset second channel } // если это вторая полуволна else { PWM_Set_Compare1(hpwm, 0); // reset first channel PWM_Set_Duty_From_DutyBridge(hpwm, hpwm->PWM_Channel2); // set second channel } //----------SLAVE PWMs----------- if (PWM_Get_Mode(hpwm, PWM_PHASE_MODE)) { // SET PHASE 2 (B) PWM_SlaveHandleTypeDef* hspwm = PWM_Set_pSlaveHandle(hpwm, hpwm2); Duty = PWM_Get_Table_Element_Signed(hpwm, rotate_ind_B); // если это первая полуволна if (Duty > 0) { PWM_Set_SlaveDuty_From_DutyBridge(hspwm, hspwm->PWM_Channel1); // set first channel PWM_Set_Compare2(hspwm, 0); // reset second channel } // если это вторая полуволна else { PWM_Set_Compare1(hspwm, 0); // reset first channel PWM_Set_SlaveDuty_From_DutyBridge(hspwm, hspwm->PWM_Channel2); // set second channel } // SET PHASE 3 (C) hspwm = PWM_Set_pSlaveHandle(hpwm, hpwm3); Duty = PWM_Get_Table_Element_Signed(hpwm, rotate_ind_C); // если это первая полуволна if (Duty > 0) { PWM_Set_SlaveDuty_From_DutyBridge(hspwm, hspwm->PWM_Channel1); // set first channel PWM_Set_Compare2(hspwm, 0); // reset second channel } // если это вторая полуволна else { PWM_Set_Compare1(hspwm, 0); // reset first channel PWM_Set_SlaveDuty_From_DutyBridge(hspwm, hspwm->PWM_Channel2); // set second channel } } else { PWM_Set_Compare1(PWM_Set_pSlaveHandle(hpwm, hpwm2), 0); // reset first channel PWM_Set_Compare2(PWM_Set_pSlaveHandle(hpwm, hpwm2), 0); // reset second channel PWM_Set_Compare1(PWM_Set_pSlaveHandle(hpwm, hpwm3), 0); // reset first channel PWM_Set_Compare2(PWM_Set_pSlaveHandle(hpwm, hpwm3), 0); // reset second channel } } /** * @brief Update PWM parameters. * @note Проверка надо ли обновлять параметры ШИМ, и если надо - обновляет их. * @note This called from TIM_CTRL_Handler */ void Update_Params_For_PWM(PWM_HandleTypeDef* hpwm) { unsigned UpdateModeParams = 0; unsigned UpdateLog = 0; // READ PWM_VALUE if (hpwm->hramp.setpoint != int_to_percent(pwm_ctrl[R_PWM_CTRL_PWM_VALUE])) { hpwm->hramp.setpoint = int_to_percent(pwm_ctrl[R_PWM_CTRL_PWM_VALUE]); if ((hpwm->hramp.setpoint == 0) || // if zero - force reset pwm value (hpwm->PWM_Value != hpwm->PWM_Value)) // or if PWM_Value isnt in range { PWM_Ramp_Reset(hpwm); } // update logs params UpdateLog = 1; } // UPDATE RAMP if (hpwm->hramp.setpoint > 0) // if setpiont inst zero PWM_Ramp_ControlPWMValue(hpwm); // READ PWM_ACTIVECHANNEL_MODE uint16_t activechannesls = (MB_Read_Coil_Local(&coils_regs[0], COIL_PWM_ACTIVECHANNEL)) | (MB_Read_Coil_Local(&coils_regs[0], COIL_PWM_ACTIVECHANNEL + 1) << 1) | (MB_Read_Coil_Local(&coils_regs[0], COIL_PWM_ACTIVECHANNEL + 2) << 2); if (PWM_Get_Mode(hpwm, PWM_ACTIVECHANNEL_MODE) != (activechannesls << PWM_ACTIVECHANNEL_MODE_Pos)) { uint16_t tmpmode = hpwm->sPWM_Mode & (~PWM_ACTIVECHANNEL_MODE); tmpmode |= activechannesls << PWM_ACTIVECHANNEL_MODE_Pos; hpwm->sPWM_Mode = tmpmode; // update mode params UpdateModeParams = 1; // update logs params UpdateLog = 1; } // READ PWM_DC_MODE if (PWM_Get_Mode(hpwm, PWM_DC_MODE) != (MB_Read_Coil_Local(&coils_regs[0], COIL_PWM_DC_MODE) << PWM_DC_MODE_Pos)) { if (MB_Read_Coil_Local(&coils_regs[0], COIL_PWM_DC_MODE)) { hpwm->sPWM_Mode |= PWM_DC_MODE; } else { hpwm->sPWM_Mode &= ~PWM_DC_MODE; } // update mode params UpdateModeParams = 1; // update logs params UpdateLog = 1; } // READ PWM_BRIDGE_MODE if (PWM_Get_Mode(hpwm, PWM_BRIDGE_MODE) != (MB_Read_Coil_Local(&coils_regs[0], COIL_PWM_BRIDGE_MODE) << PWM_BRIDGE_MODE_Pos)) { if (MB_Read_Coil_Local(&coils_regs[0], COIL_PWM_BRIDGE_MODE)) { hpwm->sPWM_Mode |= PWM_BRIDGE_MODE; } else { hpwm->sPWM_Mode &= ~PWM_BRIDGE_MODE; } // update mode params UpdateModeParams = 1; // update logs params UpdateLog = 1; } // READ PWM_PHASE_MODE if (PWM_Get_Mode(hpwm, PWM_PHASE_MODE) != (MB_Read_Coil_Local(&coils_regs[0], COIL_PWM_PHASE_MODE) << PWM_PHASE_MODE_Pos)) { if (MB_Read_Coil_Local(&coils_regs[0], COIL_PWM_PHASE_MODE)) { hpwm->sPWM_Mode |= PWM_PHASE_MODE; } else { hpwm->sPWM_Mode &= ~PWM_PHASE_MODE; } // update mode params UpdateModeParams = 1; // update logs params UpdateLog = 1; } // READ PWM_POLARITY uint16_t polarity_temp = MB_Read_Coil_Local(&coils_regs[0], COIL_PWM_POLARITY); if (((hpwm->stim.htim.Instance->CCER & TIM_CCER_CC1P) || (hpwm->stim.htim.Instance->CCER & TIM_CCER_CC3P)) != (polarity_temp)) { __HAL_TIM_SET_CAPTUREPOLARITY(&hpwm->stim.htim, hpwm->PWM_Channel1, polarity_temp << 1); __HAL_TIM_SET_CAPTUREPOLARITY(&hpwm->stim.htim, hpwm->PWM_Channel2, polarity_temp << 1); PWM_SlaveHandleTypeDef* shpwm = PWM_Set_pSlaveHandle(hpwm, hpwm2); __HAL_TIM_SET_CAPTUREPOLARITY(&shpwm->stim.htim, shpwm->PWM_Channel1, polarity_temp << 1); __HAL_TIM_SET_CAPTUREPOLARITY(&shpwm->stim.htim, shpwm->PWM_Channel2, polarity_temp << 1); shpwm = PWM_Set_pSlaveHandle(hpwm, hpwm3); __HAL_TIM_SET_CAPTUREPOLARITY(&shpwm->stim.htim, shpwm->PWM_Channel1, polarity_temp << 1); __HAL_TIM_SET_CAPTUREPOLARITY(&shpwm->stim.htim, shpwm->PWM_Channel2, polarity_temp << 1); } // READ TABLE_SIZE if (hpwm->Duty_Table_Size != pwm_ctrl[R_PWM_CTRL_SIN_TABLE_SIZE]) { hpwm->Duty_Table_Size = PWM_Fill_Sine_Table(&hpwm1, pwm_ctrl[R_PWM_CTRL_SIN_TABLE_SIZE]); pwm_ctrl[R_PWM_CTRL_SIN_TABLE_SIZE] = hpwm->Duty_Table_Size; } // READ DUTY_BRIDGE if (hpwm->PWM_DutyBridge != pwm_ctrl[R_PWM_CTRL_DUTY_BRIDGE]) { hpwm->PWM_DutyBridge = int_to_percent(pwm_ctrl[R_PWM_CTRL_DUTY_BRIDGE]); // update mode params UpdateModeParams = 1; // update logs params UpdateLog = 1; } // READ MIN PULSE DURATION if (hpwm->PWM_MinPulseDur != pwm_ctrl[R_PWM_CTRL_MIN_PULSE_DUR]) { hpwm->PWM_MinPulseDur = pwm_ctrl[R_PWM_CTRL_MIN_PULSE_DUR]; // update mode params UpdateModeParams = 1; // update logs params UpdateLog = 1; } // READ MAX PULSE DURATION if ((hpwm->PWM_MaxPulseDur != pwm_ctrl[R_PWM_CTRL_MAX_PULSE_DUR]) && (pwm_ctrl[R_PWM_CTRL_MAX_PULSE_DUR] <= PWM_Get_Autoreload(hpwm)) && (pwm_ctrl[R_PWM_CTRL_MAX_PULSE_DUR] != 0)) { hpwm->PWM_MaxPulseDur = pwm_ctrl[R_PWM_CTRL_MAX_PULSE_DUR]; // update mode params UpdateModeParams = 1; // update logs params UpdateLog = 1; } else if (((hpwm->PWM_MaxPulseDur != PWM_Get_Autoreload(hpwm)) && (pwm_ctrl[R_PWM_CTRL_MAX_PULSE_DUR] == 0)) || ((hpwm->PWM_MaxPulseDur != PWM_Get_Autoreload(hpwm)) && (pwm_ctrl[R_PWM_CTRL_MAX_PULSE_DUR] > PWM_Get_Autoreload(hpwm)))) { hpwm->PWM_MaxPulseDur = PWM_Get_Autoreload(hpwm); // update mode params UpdateModeParams = 1; } // READ DEAD TIME if (hpwm->PWM_DeadTime != pwm_ctrl[R_PWM_CTRL_DEAD_TIME]) { hpwm->PWM_DeadTime = pwm_ctrl[R_PWM_CTRL_DEAD_TIME]; } // UPDATE PWM PARAMS if (UpdateModeParams) { // UPDATE DUTY TABLE SCALE PWM_Update_DutyTableScale(hpwm); // update logs params UpdateLog = 1; } // UPDATE LOG PARAMS if (UpdateLog) { // set logs params Set_Log_Params(); } } /** * @brief PID for ramp. * @param hpwm - указатель на хендл ШИМ. * @note ПИД-регулятор, который управляет скважностью ШИМ и не дает её изменяться резко. */ void PWM_Ramp_ControlPWMValue(PWM_HandleTypeDef* hpwm) { /* * Error signal */ float error = hpwm->hramp.setpoint - hpwm->PWM_Value; /* * Proportional */ float proportional = hpwm->hramp.Kp * error; /* Limiting the accelerate */ if (error > hpwm->hramp.limMaxInt) { error = hpwm->hramp.limMaxInt; } else if (error < hpwm->hramp.limMinInt) { error = hpwm->hramp.limMinInt; } /* * Integral */ hpwm->hramp.integrator = hpwm->hramp.integrator + 0.5f * hpwm->hramp.Ki * hpwm->hramp.SampleT * (error + hpwm->hramp.prevError); /* Anti-wind-up via integrator clamping */ if (hpwm->hramp.integrator > hpwm->hramp.limMax) { hpwm->hramp.integrator = hpwm->hramp.limMax; } else if (hpwm->hramp.integrator < hpwm->hramp.limMin) { hpwm->hramp.integrator = hpwm->hramp.limMin; } /* * Derivative (band-limited differentiator) */ hpwm->hramp.differentiator = -(2.0f * hpwm->hramp.Kd * (hpwm->PWM_Value - hpwm->hramp.prevMeasurement) /* Note: derivative on measurement, therefore minus sign in front of equation! */ + (2.0f * hpwm->hramp.tau - hpwm->hramp.SampleT) * hpwm->hramp.differentiator) / (2.0f * hpwm->hramp.tau + hpwm->hramp.SampleT); /* * Compute output and apply limits */ hpwm->PWM_Value = proportional + hpwm->hramp.integrator + hpwm->hramp.differentiator; if (hpwm->PWM_Value > hpwm->hramp.limMax) { hpwm->PWM_Value = hpwm->hramp.limMax; } else if (hpwm->PWM_Value < hpwm->hramp.limMin) { hpwm->PWM_Value = hpwm->hramp.limMin; } /* Store error and measurement for later use */ hpwm->hramp.prevError = error; hpwm->hramp.prevMeasurement = hpwm->PWM_Value; // /* set PWM Value output */ // *hpwm->hramp.out; } /** * @brief Reset PID for ramp. * @param hpwm - указатель на хендл ШИМ. * @note Сбрасывает переменные ПИД-регулятора, чтобы потом его запустить "с чистого листа". */ void PWM_Ramp_Reset(PWM_HandleTypeDef* hpwm) { hpwm->PWM_Value = 0; /* Clear controller variables */ hpwm->hramp.integrator = 0.0f; hpwm->hramp.prevError = 0.0f; hpwm->hramp.differentiator = 0.0f; hpwm->hramp.prevMeasurement = 0.0f; } /** * @brief reInitialization of PWM TIM. * @param hpwm - указатель на хендл ШИМ. * @note Перенастраивает таймер согласно принятным настройкам в pwm_ctrl * ШИМ генерируется на одном канале. */ void PWM_Sine_ReInit(PWM_HandleTypeDef* hpwm) { Trace_PWM_reInit_Enter(); TIM_Base_MspDeInit(&hpwm->stim.htim); hpwm1.stim.sTickBaseMHz = TIMER_PWM_TICKBASE; hpwm1.sConfigOC.OCPolarity = MB_Read_Coil_Local(&coils_regs[0], COIL_PWM_POLARITY) << TIM_CCER_CC1P_Pos; TIM_Base_Init(&hpwm->stim); TIM_Output_PWM_Init(&hpwm->stim.htim, &hpwm->sConfigOC, hpwm->PWM_Channel1, hpwm->GPIOx, hpwm->GPIO_PIN_X1); TIM_Output_PWM_Init(&hpwm->stim.htim, &hpwm->sConfigOC, hpwm->PWM_Channel2, hpwm->GPIOx, hpwm->GPIO_PIN_X2); PWM_Update_DutyTableScale(hpwm); //----------TIMERS START------------- HAL_TIM_Base_Start_IT(&hpwm1.stim.htim); // timer for PWM HAL_TIM_PWM_Start(&hpwm1.stim.htim, hpwm->PWM_Channel1); // PWM channel 1 HAL_TIM_PWM_Start(&hpwm1.stim.htim, hpwm->PWM_Channel2); // PWM channel 2 Trace_PWM_reInit_Exit(); } /** * @brief Getting ind for Duty Table. * @param hpwm - указатель на хендл ШИМ. * @param FreqTIM - частота таймера ШИМ. * @note Рассчитывает индекс для таблицы скважностей. * PWM_Value в hpwm - частота с которой эта таблица должна выводиться на ШИМ * @note This called from TIM_PWM_Handler */ uint32_t PWM_Get_Duty_Table_Ind(PWM_HandleTypeDef* hpwm, float FreqTIM) { float sine_ind_step; // calc ind for sin table if (hpwm->PWM_Value != 0) // if there some frequency { sine_ind_step = hpwm->Duty_Table_Size / (FreqTIM / hpwm->PWM_Value); hpwm->Duty_Table_Ind += sine_ind_step; } else return hpwm->Duty_Table_Size; // overflow check if (hpwm->Duty_Table_Ind >= hpwm->Duty_Table_Size) hpwm->Duty_Table_Ind -= hpwm->Duty_Table_Size; if (hpwm->Duty_Table_Ind >= hpwm->Duty_Table_Size) hpwm->Duty_Table_Ind = 0; // if its too big (e.g. inf) if ((hpwm->Duty_Table_Ind >= 0xFFFF) || (hpwm->Duty_Table_Ind != hpwm->Duty_Table_Ind)) // in nan case hpwm->Duty_Table_Ind = 0; return hpwm->Duty_Table_Ind; } /** * @brief Create Dead Time when switches channels. * @param hpwm - указатель на хендл ШИМ. */ void PWM_CreateDeadTime(PWM_HandleTypeDef* hpwm, float* LocalDeadTimeCnt, unsigned* LocalActiveChannel) { // get current active channel hpwm->fActiveChannel = (PWM_Get_Compare2(hpwm) != 0); // if channel two is active - write 1, otherwise - 0 // when channels are swithed and no dead time currently active if (*LocalActiveChannel != hpwm->fActiveChannel) { // update active channel *LocalActiveChannel = hpwm->fActiveChannel; // set deadtime *LocalDeadTimeCnt = hpwm->PWM_DeadTime; Trace_PWM_DeadTime_Enter(); } // decrement dead time *LocalDeadTimeCnt -= (PWM_Get_Autoreload(hpwm) + 1) * hpwm->stim.sTickBaseMHz; if (*LocalDeadTimeCnt > 0) // if dead time is still active { // reset all channels // reset channels PWM_Set_Compare1(hpwm, 0); PWM_Set_Compare2(hpwm, 0); } else // if dead time is done { // set it to zero *LocalDeadTimeCnt = 0; Trace_PWM_DeadTime_Exit(); } } /** * @brief Filling table with one period of sinus values. * @param hpwm - указатель на хендл ШИМ. * @param table_size - размер таблицы. * @note Формирует таблицу синусов размером table_size. */ uint32_t PWM_Fill_Sine_Table(PWM_HandleTypeDef* hpwm, uint32_t table_size) { if ((hpwm == NULL) || (hpwm->pDuty_Table_Origin == NULL) || (table_size == 0)) { return 0; } if (table_size > SIN_TABLE_SIZE_MAX) table_size = SIN_TABLE_SIZE_MAX; hpwm->Duty_Table_Size = table_size; float pi_step = 2 * M_PI / (hpwm->Duty_Table_Size); float pi_val = 0; float sin_koef = 0; uint32_t sin_val = 0; // fill table with sinus for (int i = 0; i < hpwm->Duty_Table_Size; i++) { // rotate pi pi_val += pi_step; // calc sin value sin_koef = (float)0xFFFF; sin_val = (sin(pi_val) + 1) * sin_koef / 2; sin_table[i] = sin_val; } // fill rest of table with zeros for (int i = hpwm->Duty_Table_Size; i < SIN_TABLE_SIZE_MAX; i++) sin_table[i] = 0; // if second channel is enabled PWM_Update_DutyTableScale(hpwm); return hpwm->Duty_Table_Size; } /** * @brief Calc and update new Duty Table Scale. * @param hpwm - указатель на хендл ШИМ. * @note Используется, когда изменяется значение регистра ARR. */ void PWM_Update_DutyTableScale(PWM_HandleTypeDef* hpwm) { // UPDATE DUTY TABLE SCALE if (PWM_Get_Mode(hpwm, PWM_BRIDGE_MODE)) // if second channel is enabled { hpwm->Duty_Table_Scale = PWM_Calc_Duty_Scale(&hpwm1, 0x8000); } else { hpwm->Duty_Table_Scale = PWM_Calc_Duty_Scale(&hpwm1, 0xFFFF); } // for case if min pulse dur is too big and scale is negative if (hpwm->Duty_Table_Scale < 0) hpwm->Duty_Table_Scale = 1; } //------------------------------------------------------------------- //-----------------------THREEPHASE FUNCTIONS------------------------ /** * @brief Initialization of Slave PWM TIM. * @param hspwm - указатель на хендл слейв ШИМ. * @note Вызывает функции инициализации и включения слейв ШИМ. */ void PWM_SlavePhase_Init(PWM_SlaveHandleTypeDef* hspwm) { TIM_Base_Init(&hspwm->stim); TIM_Output_PWM_Init(&hspwm->stim.htim, &hspwm->hMasterPWM->sConfigOC, hspwm->PWM_Channel1, hspwm->GPIOx, hspwm->GPIO_PIN_X1); TIM_Output_PWM_Init(&hspwm->stim.htim, &hspwm->hMasterPWM->sConfigOC, hspwm->PWM_Channel2, hspwm->GPIOx, hspwm->GPIO_PIN_X2); // if three phase enables //----------TIMERS START------------- HAL_TIM_Base_Start(&hspwm->stim.htim); HAL_TIM_PWM_Start(&hspwm->stim.htim, hspwm->PWM_Channel1); // PWM channel 1 HAL_TIM_PWM_Start(&hspwm->stim.htim, hspwm->PWM_Channel2); // PWM channel 2 if (PWM_Get_Mode(hspwm->hMasterPWM, PWM_PHASE_MODE) == 0) // if three phase disabled { PWM_Set_Compare1(hspwm, 0); // reset first channel PWM_Set_Compare2(hspwm, 0); // reset second channel } } /** * @brief reInitialization of Slave PWM TIM. * @param hspwm - указатель на хендл слейв ШИМ. * @note Перенастраивает таймер согласно принятным настройкам в pwm_ctrl. */ void PWM_SlavePhase_reInit(PWM_SlaveHandleTypeDef* hspwm) { PWM_Slave_CopyTimSetting(hspwm, sTimFreqHz); TIM_Base_MspDeInit(&hspwm->stim.htim); PWM_SlavePhase_Init(hspwm); } /** * @brief Set Duty from table on Slave PWM at one channel by sin_ind of the Master PWM. * @param hspwm - указатель на хендл слейв ШИМ. * @param sin_ind - индекс таблицы для Мастер ШИМ. * @note Индекс для свейл ШИМ расчитывается в самой функции. */ uint16_t PWM_SlavePhase_Calc_TableInd(PWM_SlaveHandleTypeDef* hspwm, uint16_t rotate_ind_Phase) { // if three phase enables if (hspwm->Duty_Shift_Ratio > 0) rotate_ind_Phase += hspwm->hMasterPWM->Duty_Table_Size * hspwm->Duty_Shift_Ratio; else rotate_ind_Phase += hspwm->hMasterPWM->Duty_Table_Size * (1 + hspwm->Duty_Shift_Ratio); // overflow check if (rotate_ind_Phase > hspwm->hMasterPWM->Duty_Table_Size) rotate_ind_Phase -= hspwm->hMasterPWM->Duty_Table_Size; if (rotate_ind_Phase > hspwm->hMasterPWM->Duty_Table_Size) rotate_ind_Phase = 0;; return rotate_ind_Phase; // // PWM_Set_SlaveDuty_From_Table(hspwm, sin_ind); // set first channel } /** * @brief Check is all Slave channels works properly. * @param hspwm - указатель на хендл слейв ШИМ. * @note Проверка работает ли только один из каналов, и проверка чтобы CCRx <= ARR * @note В мастере проверка происходит напрямую в PWM_Handler. */ void PWM_SlavePhase_Check_Channels(PWM_SlaveHandleTypeDef* hspwm) { uint16_t min_duty = PWM_Calc_Min_Duty(hspwm->hMasterPWM); uint16_t max_duty = PWM_Calc_Max_Duty(hspwm->hMasterPWM); // IF FIRST CHANNEL IS ACRIVE if (PWM_Get_Compare1(hspwm) != 0) { // Duty shoud be bigger or equeal than min duration if (PWM_Get_Compare1(hspwm) < min_duty) PWM_Set_Compare1(hspwm, min_duty); // Duty shoud be less or equeal than ARR-min duration if (PWM_Get_Compare1(hspwm) > max_duty) PWM_Set_Compare1(hspwm, max_duty); } // IF SECOND CHANNEL IS ACRIVE else if (PWM_Get_Compare2(hspwm) != 0) // Duty shoud be bigger or equeal than min duration if (PWM_Get_Compare2(hspwm) < min_duty) PWM_Set_Compare2(hspwm, min_duty); // Duty shoud be less or equeal than ARR if (PWM_Get_Compare2(hspwm) > max_duty) PWM_Set_Compare2(hspwm, max_duty); // IF BOTH CHANNEL IS ACRIVE if ((PWM_Get_Compare1(hspwm) != 0) && (PWM_Get_Compare2(hspwm) != 0)) { // Only one channel shoud be active so disable all PWM_Set_Compare1(hspwm, 0); PWM_Set_Compare2(hspwm, 0); } } /** * @brief Create Dead Time for Slave PWM when switches channels. * @param hspwm - указатель на хендл слейв ШИМ. * @param LocalDeadTimeCnt - указатель на переменную для отсчитывания дедтайма. * @param LocalActiveChannel - указатель на переменную для отслеживания смены канала. * @note Аналог функции PWM_CreateDeadTime но для слейв ШИМов. */ void PWM_SlavePhase_CreateDeadTime(PWM_SlaveHandleTypeDef* hspwm, float* LocalDeadTimeCnt, unsigned* LocalActiveChannel) { // get current active channel hspwm->fActiveChannel = (PWM_Get_Compare2(hspwm) != 0); // if channel two is active - write 1, otherwise - 0 // when channels are swithed and no dead time currently active if (*LocalActiveChannel != hspwm->fActiveChannel) { // update active channel *LocalActiveChannel = hspwm->fActiveChannel; // set deadtime *LocalDeadTimeCnt = hspwm->hMasterPWM->PWM_DeadTime; Trace_PWM_DeadTime_Enter(); } // decrement dead time *LocalDeadTimeCnt -= (PWM_Get_Autoreload(hspwm) + 1) * hspwm->hMasterPWM->stim.sTickBaseMHz; if (*LocalDeadTimeCnt > 0) // if dead time is still active { // reset all channels // reset channels PWM_Set_Compare1(hspwm, 0); PWM_Set_Compare2(hspwm, 0); } else // if dead time is done { // set it to zero *LocalDeadTimeCnt = 0; Trace_PWM_DeadTime_Exit(); } } //------------------------------------------------------------------- //------------------------HANDLERS FUNCTIONS------------------------- //---------------PWM TIMER----------------- #if (PWM_MASTER_TIM_NUMB == 1) || (PWM_MASTER_TIM_NUMB == 10) // choose handler for TIM void TIM1_UP_TIM10_IRQHandler(void) #elif (PWM_MASTER_TIM_NUMB == 2) void TIM2_IRQHandler(void) #elif (PWM_MASTER_TIM_NUMB == 3) void TIM3_IRQHandler(void) #elif (PWM_MASTER_TIM_NUMB == 4) void TIM4_IRQHandler(void) #elif (PWM_MASTER_TIM_NUMB == 5) void TIM5_IRQHandler(void) #elif (PWM_MASTER_TIM_NUMB == 6) void TIM6_DAC_IRQHandler(void) #elif (PWM_MASTER_TIM_NUMB == 7) void TIM7_IRQHandler(void) #elif (PWM_MASTER_TIM_NUMB == 8) || (PWM_MASTER_TIM_NUMB == 13) void TIM8_UP_TIM13_IRQHandler(void) #elif (PWM_MASTER_TIM_NUMB == 1) || (PWM_MASTER_TIM_NUMB == 9) void TIM1_BRK_TIM9_IRQHandler(void) #elif (PWM_MASTER_TIM_NUMB == 1) || (PWM_MASTER_TIM_NUMB == 11) void TIM1_TRG_COM_TIM11_IRQHandler(void) #elif (PWM_MASTER_TIM_NUMB == 8) || (PWM_MASTER_TIM_NUMB == 12) void TIM8_BRK_TIM12_IRQHandler(void) #elif (PWM_MASTER_TIM_NUMB == 8) || (PWM_MASTER_TIM_NUMB == 14) void TIM8_TRG_COM_TIM14_IRQHandler(void) #endif { /* TIM_PWM_Handler */ Trace_PWM_TIM_Enter(); HAL_TIM_IRQHandler(&hpwm1.stim.htim); PWM_Handler(&hpwm1); Trace_PWM_TIM_Exit(); }