#include "pwm.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; 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.pDuty_Table_Origin = SIN_TABLE_ORIGIN; //---------PWM TIMER1 INIT------------ // channels settings hpwm1.sConfigOC.OCMode = TIM_OCMODE_PWM1; hpwm1.sConfigOC.Pulse = 0; hpwm1.sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; hpwm1.sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; // tim1 settings hpwm1.stim.htim.Instance = TIMER_PWM_INSTANCE; hpwm1.stim.sTimMode = TIM_IT_MODE; hpwm1.stim.sTickBaseMHz = TIMER_PWM_TICKBASE; hpwm1.stim.sTimAHBFreqMHz = TIMER_PWM_AHB_FREQ; hpwm1.stim.sTimFreqHz = HZ_TIMER_PWM; hpwm1.GPIOx = TIMER_PWM_GPIOx; hpwm1.GPIO_PIN_X1 = TIMER_PWM_GPIO_PIN_X1; hpwm1.GPIO_PIN_X2 = TIMER_PWM_GPIO_PIN_X2; hpwm1.PWM_Channel1 = TIMER_PWM_TIM_CHANNEL1; hpwm1.PWM_Channel2 = TIMER_PWM_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 = TIMER_PWM2_INSTANCE; hpwm2.GPIOx = TIMER_PWM2_GPIOx; hpwm2.GPIO_PIN_X1 = TIMER_PWM2_GPIO_PIN_X1; hpwm2.GPIO_PIN_X2 = TIMER_PWM2_GPIO_PIN_X2; hpwm2.PWM_Channel1 = TIMER_PWM2_TIM_CHANNEL1; hpwm2.PWM_Channel2 = TIMER_PWM2_TIM_CHANNEL2; hpwm2.Duty_Shift_Ratio = (float)2/3; hpwm3.hMasterPWM = &hpwm1; hpwm3.stim = hpwm1.stim; hpwm3.stim.htim.Instance = TIMER_PWM3_INSTANCE; hpwm3.GPIOx = TIMER_PWM3_GPIOx; hpwm3.GPIO_PIN_X1 = TIMER_PWM3_GPIO_PIN_X1; hpwm3.GPIO_PIN_X2 = TIMER_PWM3_GPIO_PIN_X2; hpwm3.PWM_Channel1 = TIMER_PWM3_TIM_CHANNEL1; hpwm3.PWM_Channel2 = TIMER_PWM3_TIM_CHANNEL2; hpwm3.Duty_Shift_Ratio = (float)-2/3; 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) { //------------SINUS MODE------------- if(PWM_Get_Mode(&hpwm1,PWM_DC_MODE) == 0) { if(hpwm->PWM_Value != 0) // if there some frequency { unsigned sin_ind = PWM_Get_Duty_Table_Ind(hpwm, hpwm->stim.sTimFreqHz); // overflow check if(sin_ind >= hpwm->Duty_Table_Size) sin_ind -= hpwm->Duty_Table_Size; if(sin_ind >= hpwm->Duty_Table_Size) // if its still overflow reset it sin_ind = 0; // if unsigned sine enabled if(PWM_Get_Mode(hpwm, PWM_CH_MODE) == 0) { // set pwm duty PWM_Set_Duty_From_Table(hpwm, sin_ind); // set first channel PWM_SlavePhase_Set_DutyTable_Unsigned(PWM_Set_pSlaveHandle(hpwm,hpwm2), sin_ind); PWM_SlavePhase_Set_DutyTable_Unsigned(PWM_Set_pSlaveHandle(hpwm,hpwm3), sin_ind); } // if signed sine enabled else { int Duty = PWM_Get_Table_Element_Signed(hpwm, sin_ind); if(Duty >= 0) { PWM_Set_Compare1(hpwm, Duty+PWM_Sine_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_Sine_Calc_Min_Duty(hpwm)); // set second channel } PWM_SlavePhase_Set_DutyTable_Signed(PWM_Set_pSlaveHandle(hpwm,hpwm2), sin_ind); PWM_SlavePhase_Set_DutyTable_Signed(PWM_Set_pSlaveHandle(hpwm,hpwm3), sin_ind); } } else // if freq = 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 } } //-----------PWM DC MODE------------- 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 // if second channel enabled if(PWM_Get_Mode(hpwm, PWM_CH_MODE)) { PWM_Set_Compare1(hpwm, 0); // reset first channel PWM_Set_Duty_From_Percent(hpwm, hpwm->PWM_Channel2); // set second channel } // if first channel enabled else { PWM_Set_Duty_From_Percent(hpwm, hpwm->PWM_Channel1); // set first channel PWM_Set_Compare2(hpwm, 0); // reset second channel } } //-----CHECK CHANNELS FOR ERRORS----- // Duty shoud be less or equeal than ARR if (PWM_Get_Compare1(hpwm)>PWM_Get_Autoreload(hpwm)) PWM_Set_Compare1(hpwm, PWM_Get_Autoreload(hpwm)); // Duty shoud be less or equeal than ARR if (PWM_Get_Compare2(hpwm)>PWM_Get_Autoreload(hpwm)) PWM_Set_Compare2(hpwm, PWM_Get_Autoreload(hpwm)); // Only one channel shoud be active if((PWM_Get_Compare1(hpwm) != 0) && (PWM_Get_Compare2(hpwm) != 0)) { 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 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_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_CH_MODE if(PWM_Get_Mode(hpwm, PWM_CH_MODE) != (MB_Read_Coil_Local(&coils_regs[0], COIL_PWM_CH_MODE) << PWM_CH_MODE_Pos)) { if(MB_Read_Coil_Local(&coils_regs[0], COIL_PWM_CH_MODE)) { hpwm->sPWM_Mode |= PWM_CH_MODE; } else { hpwm->sPWM_Mode &= ~PWM_CH_MODE; } // update mode params UpdateModeParams = 1; // update logs params UpdateLog = 1; } // READ PWM_CH_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_VALUE if(hpwm->PWM_Value != int_to_percent(pwm_ctrl[R_PWM_CTRL_PWM_VALUE])) { hpwm->PWM_Value = int_to_percent(pwm_ctrl[R_PWM_CTRL_PWM_VALUE]); // update logs params UpdateLog = 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 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 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 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; 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; uint32_t sine_ind; // calc ind for sin table sine_ind_step = hpwm->Duty_Table_Size/(FreqTIM/hpwm->PWM_Value); hpwm->Duty_Table_Ind += sine_ind_step; if(hpwm->Duty_Table_Ind >= hpwm->Duty_Table_Size) hpwm->Duty_Table_Ind -= hpwm->Duty_Table_Size; // if its too big (e.g. inf) if(hpwm->Duty_Table_Ind >= 0xFFFF) 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_CH_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 Индекс для свейл ШИМ расчитывается в самой функции. */ void PWM_SlavePhase_Set_DutyTable_Unsigned(PWM_SlaveHandleTypeDef *hspwm, uint16_t sin_ind) { // if three phase enables if (PWM_Get_Mode(hspwm->hMasterPWM, PWM_PHASE_MODE)) { if(hspwm->Duty_Shift_Ratio > 0) sin_ind += hspwm->hMasterPWM->Duty_Table_Size*hspwm->Duty_Shift_Ratio; else sin_ind += hspwm->hMasterPWM->Duty_Table_Size*(1+hspwm->Duty_Shift_Ratio); // overflow check if(sin_ind > hspwm->hMasterPWM->Duty_Table_Size) sin_ind -= hspwm->hMasterPWM->Duty_Table_Size; PWM_Set_SlaveDuty_From_Table(hspwm, sin_ind); // set first channel } } /** * @brief Set Duty from table on Slave PWM at two channel by sin_ind of the Master PWM. * @param hspwm - указатель на хендл слейв ШИМ. * @param sin_ind - индекс таблицы для Мастер ШИМ. * @note Индекс для свейл ШИМ расчитывается в самой функции. */ void PWM_SlavePhase_Set_DutyTable_Signed(PWM_SlaveHandleTypeDef *hspwm, uint16_t sin_ind) { int Duty; // if three phase enables if (PWM_Get_Mode(hspwm->hMasterPWM, PWM_PHASE_MODE)) { if(hspwm->Duty_Shift_Ratio > 0) sin_ind += hspwm->hMasterPWM->Duty_Table_Size*hspwm->Duty_Shift_Ratio; else sin_ind += hspwm->hMasterPWM->Duty_Table_Size*(1+hspwm->Duty_Shift_Ratio); // overflow check if(sin_ind >= hspwm->hMasterPWM->Duty_Table_Size) sin_ind -= hspwm->hMasterPWM->Duty_Table_Size; Duty = PWM_Get_Table_Element_Signed(hspwm->hMasterPWM, sin_ind); // если это первая полуволна if(Duty > 0) { PWM_Set_Compare1(hspwm, Duty+PWM_Sine_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_Sine_Calc_Min_Duty(hspwm->hMasterPWM)); // set second channel } } else // if three phase disabled { PWM_Set_Compare1(hspwm, 0); // reset first channel PWM_Set_Compare2(hspwm, 0); // reset second 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) { // if three phase enables if (PWM_Get_Mode(hspwm->hMasterPWM, PWM_PHASE_MODE)) { // Duty shoud be less or equeal than ARR if (PWM_Get_Compare1(hspwm)>PWM_Get_Autoreload(hspwm)) PWM_Set_Compare1(hspwm, PWM_Get_Autoreload(hspwm)); // Duty shoud be less or equeal than ARR if (PWM_Get_Compare2(hspwm)>PWM_Get_Autoreload(hspwm)) PWM_Set_Compare2(hspwm, PWM_Get_Autoreload(hspwm)); // Only one channel shoud be active if((PWM_Get_Compare1(hspwm) != 0) && (PWM_Get_Compare2(hspwm) != 0)) { // reset channels PWM_Set_Compare1(hspwm, 0); // reset first channel PWM_Set_Compare2(hspwm, 0); // reset second channel } } else // if three phase disabled { // reset channels PWM_Set_Compare1(hspwm, 0); // reset first channel PWM_Set_Compare2(hspwm, 0); // reset second channel } } /** * @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----------------- void TIM4_IRQHandler(void) { Trace_PWM_TIM_Enter(); HAL_TIM_IRQHandler(&hpwm1.stim.htim); PWM_Handler(&hpwm1); Trace_PWM_TIM_Exit(); } //------------------------------------------------------------------- //------------------------------------------------------------------- //-----------------------------OUTDATE------------------------------- #ifdef OUTDATE /** * @brief First set up of PWM Single Channel. * @note Первый инит ШИМ. Заполняет структуры и инициализирует таймер для генерации синуоидального ШИМ. * Скважность ШИМ меняется по закону синусоиды, сдвинутой в положительную область (от 0 до 2) * ШИМ генерируется на одном канале. * @note This called from main */ void PWM_SineSingChannel_FirstInit(void) { hpwm1.pDuty_Table_Origin = SIN_TABLE_ORIGIN; //---------PWM TIMER1 INIT------------ // channel settings hpwm1.sConfigOC.OCMode = TIM_OCMODE_PWM1; hpwm1.sConfigOC.Pulse = 0; hpwm1.sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; hpwm1.sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; // tim1 settings hpwm1.stim.htim.Instance = TIMER_PWM_INSTANCE; hpwm1.stim.sTimMode = TIM_IT_MODE; hpwm1.stim.sTickBaseMHz = TIM_TickBase_1US; hpwm1.stim.sTimAHBFreqMHz = 72; hpwm1.stim.sTimFreqHz = HZ_TIMER_PWM; hpwm1.GPIOx = GPIOD; hpwm1.GPIO_PIN_X1 = GPIO_PIN_12; TIM_Base_Init(&hpwm1.stim); TIM_Output_PWM_Init(&hpwm1.stim.htim, &hpwm1.sConfigOC, hpwm->PWM_Channel1, hpwm1.GPIOx, hpwm1.GPIO_PIN_X1); //----------TIMERS START------------- HAL_TIM_PWM_Start_IT(&hpwm1.stim.htim, hpwm->PWM_Channel1); // timer for PWM } #ifdef SINE_THREE_PHASE_PWM_ENABLE //---------PWM TIMER2 INIT------------ // tim2 settings hpwm2 = hpwm1; hpwm2.stim.htim.Instance = TIM5; hpwm2.GPIOx = GPIOA; hpwm2.GPIO_PIN_X = GPIO_PIN_0; TIM_Base_Init(&hpwm2.stim); TIM_Output_PWM_Init(&hpwm2.stim.htim, &hpwm2.sConfigOC, TIM_CHANNEL_1, hpwm2.GPIOx, hpwm2.GPIO_PIN_X); //---------PWM TIMER3 INIT------------ // tim3 settings hpwm3 = hpwm2; hpwm3.stim.htim.Instance = TIM8; hpwm3.GPIOx = GPIOC; hpwm3.GPIO_PIN_X = GPIO_PIN_6; TIM_Base_Init(&hpwm3.stim); TIM_Output_PWM_Init(&hpwm3.stim.htim, &hpwm3.sConfigOC, TIM_CHANNEL_1, hpwm3.GPIOx, hpwm3.GPIO_PIN_X); HAL_TIM_PWM_Start(&hpwm2.stim.htim, TIM_CHANNEL_1); // timer for PWM HAL_TIM_PWM_Start(&hpwm3.stim.htim, TIM_CHANNEL_1); // timer for PWM #endif // SINE_THREE_PHASE_PWM_ENABLE void PWM_Threephase_Init(void) { #ifdef INTERNAL_THREE_PHASE_PWM_ENABLE TIM_OC_InitTypeDef sPWMConfigOC = {0}; TIM_OC_InitTypeDef sOCConfigOC = {0}; int us100Time = 10000/TIM_CTRL.sTimFreqHz; // 1/TIM_CTRL.sTimFreqHz * 10^6 - Sample time in us // PWM CHANNEL SETTINGS sPWMConfigOC.OCMode = TIM_OCMODE_PWM1; sPWMConfigOC.Pulse = us100Time/2; sPWMConfigOC.OCPolarity = TIM_OCPOLARITY_LOW; sPWMConfigOC.OCFastMode = TIM_OCFAST_DISABLE; // CC CHANNEL SETTINGS sOCConfigOC.OCMode = TIM_OCMODE_ACTIVE; sOCConfigOC.Pulse = (2*us100Time-1) / 3; sOCConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; // TIMER1 PWM MASTER INIT TIM_3PWM1.htim = &tim_3pwm1; TIM_3PWM1.htim->Instance = TIM1; TIM_3PWM1.htim->Init.Prescaler = 7200-1; // 1 us TIM_3PWM1.htim->Init.Period = us100Time-1; // period in us = Sample time in us TIM_3PWM1.sMasterConfig.MasterOutputTrigger = TIM_TRGO_OC2REF; TIM_3PWM1.sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; TIM_3PWM1.sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH; TIM_Base_Init(&TIM_3PWM1); TIM_Output_PWM_Init(TIM_3PWM1.htim, &sPWMConfigOC, TIM_CHANNEL_1, GPIOE, GPIO_PIN_9); HAL_TIM_OC_ConfigChannel(TIM_3PWM1.htim, &sOCConfigOC, TIM_CHANNEL_2); // TIMER2 PWM SLAVE INIT TIM_3PWM2 = TIM_3PWM1; TIM_3PWM2.htim = &tim_3pwm2; *TIM_3PWM2.htim = *TIM_3PWM1.htim; TIM_3PWM2.htim->Instance = TIM2; TIM_3PWM1.TIM_MODE = TIM_DEFAULT; TIM_3PWM2.sSlaveConfig.SlaveMode = TIM_SLAVEMODE_TRIGGER; TIM_3PWM2.sSlaveConfig.InputTrigger = TIM_TS_ITR0; TIM_Base_Init(&TIM_3PWM2); TIM_Output_PWM_Init(TIM_3PWM2.htim, &sPWMConfigOC, TIM_CHANNEL_1, GPIOA, GPIO_PIN_5); HAL_TIM_OC_ConfigChannel(TIM_3PWM2.htim, &sOCConfigOC, TIM_CHANNEL_2); // TIMER3 PWM SLAVE INIT TIM_3PWM3 = TIM_3PWM2; TIM_3PWM3.htim = &tim_3pwm3; *TIM_3PWM3.htim = *TIM_3PWM2.htim; TIM_3PWM3.htim->Instance = TIM3; TIM_3PWM3.sSlaveConfig.InputTrigger = TIM_TS_ITR1; TIM_Base_Init(&TIM_3PWM3); TIM_Output_PWM_Init(TIM_3PWM3.htim, &sPWMConfigOC, TIM_CHANNEL_1, GPIOA, GPIO_PIN_6); hpwm1.Duty_Table_Size = PWM_Fill_Sine_Table(&sin_table, SIN_TABLE_SIZE_MAX); // TIMERS START HAL_TIM_OC_Start(TIM_3PWM3.htim, TIM_CHANNEL_2); HAL_TIM_PWM_Start(TIM_3PWM3.htim, TIM_CHANNEL_1); HAL_TIM_PWM_Start(TIM_3PWM2.htim, TIM_CHANNEL_1); HAL_TIM_OC_Start(TIM_3PWM2.htim, TIM_CHANNEL_2); HAL_TIM_OC_Start(TIM_3PWM1.htim, TIM_CHANNEL_2); HAL_TIM_PWM_Start(TIM_3PWM1.htim, TIM_CHANNEL_1); #endif // INTERNAL_THREE_PHASE_PWM_ENABLE } #endif