/********************************MODBUS************************************* Данный файл содержит объявления базовых функции и дефайны для реализации MODBUS. Данный файл необходимо подключить в rs_message.h. После подключать rs_message.h к основному проекту. ***************************************************************************/ #ifndef __PWM_H_ #define __PWM_H_ #include "control.h" extern uint32_t sin_table[SIN_TABLE_SIZE_MAX]; #define int_to_percent(_int_) ((float)_int_/100) ///////////////////////////////////////////////////////////////////// ////////////////////////////---DEFINES---//////////////////////////// //----------------------------PWM HANDLE----------------------------// /** * @brief Calc duration of minimum pulse in ticks. * @param _hpwm_ - указатель на хендл pwm. * @return _val_ - количество тиков кратчайшего импульса. */ #define PWM_Sine_Calc_Min_Duty(_hpwm_) ((_hpwm_)->PWM_MinPulseDur/(_hpwm_)->stim.sTickBaseMHz) /** * @brief Calc Scale Koef for Table & AUTORELOAD REGISTER * @param _hpwm_ - указатель на хендл pwm. * @param _scale_ - верхняя граница диапазона значений. * @return _koef_ - коэффициент для масштабирования. * @note Данный макрос рассчитывает коэффициент для приведения значений с диапазоном [0,_scale_] к регистру автозагрузки с диапазоном [0,ARR]. * @note Если задана минимальная длительность импульса в тактах n, она вычитается из ARR: [0, ARR-2*n] И потом регистр ARR заполняется так, что диапазон его значений будет [n, ARR-n] @ref PWM_Get_Table_Element_Unsigned */ #define PWM_Calc_Duty_Scale(_hpwm_, _scale_) ((float)PWM_Get_Autoreload(_hpwm_)-2*PWM_Sine_Calc_Min_Duty(_hpwm_))/(_scale_) /** * @brief Get Table Element Scaled corresponding to TIM ARR register * @param _hpwm_ - указатель на хендл pwm. * @param _ind_ - номер элемента из таблицы скважностей. * @return _val_ - масштабированный под регистры таймера значение. * @note Если задана минимальная длительность импульса в тактах n, то регистр ARR заполняется так, что диапазон его значений будет [n, ARR-n] */ #define PWM_Get_Table_Element_Unsigned(_hpwm_,_ind_) ((*((_hpwm_)->pDuty_Table_Origin+_ind_)*((_hpwm_)->Duty_Table_Scale))+PWM_Sine_Calc_Min_Duty(_hpwm_)) /** * @brief Get Table Element Scaled and Shifted corresponding to TIM ARR register * @param _hpwm_ - указатель на хендл pwm. * @param _ind_ - номер элемента из таблицы скважностей. * @return _val_ - масштабированный под регистры таймера значение. * @note По сути такая же как PWM_Get_Table_Element_Unsigned но добавляется сдвиг на одну амплитуду для учитывания знака. (если точнее, то сдвиг добавляется для компенсации сдвига, который имитирует знак) * @note 0x8000*(_hpwm_)->Duty_Table_Scale - т.к. первая полуволна находится в диапазоне (0x8000-0xFFFF) вычитаем константу 0x8000 с масштабированием */ #define PWM_Get_Table_Element_Signed(_hpwm_,_ind_) ((int)(*((_hpwm_)->pDuty_Table_Origin+_ind_)*((_hpwm_)->Duty_Table_Scale))-0x8000*(_hpwm_)->Duty_Table_Scale) /** * @brief Create pointer to slave PWM from pointer to void in PWM_HandleTypeDef. * @param _hpwm_ - указатель на хендл pwm. * @param _slavepwm_ - имя слейв pwm. * @return _pslavepwm_ - указатель на структуру PWM_SlaveHandleTypeDef. */ #define PWM_Set_pSlaveHandle(_hpwm_,_slavepwm_) ((PWM_SlaveHandleTypeDef *)_hpwm_->_slavepwm_) /** * @brief Copy setting from master TIM_SettingsTypeDef to slave TIM_SettingsTypeDef. * @param _hpwm_ - указатель на хендл pwm. * @return _set_ - имя настройки. */ #define PWM_Slave_CopyTimSetting(_hspwm_, _set_) ((_hspwm_)->stim._set_ = (_hspwm_)->hMasterPWM->stim._set_) //---------------------------TIMER REGS----------------------------// /** * @brief Set PWM autoreload value (max duty value). * @param _hpwm_ - указатель на хендл pwm. * @param _val_ - значение, которое нужно записать в Compare. */ #define PWM_Get_Autoreload(_hpwm_) __HAL_TIM_GET_AUTORELOAD(&((_hpwm_)->stim.htim)) /** * @brief Get PWM Duty on corresponding channel. * @param _hpwm_ - указатель на хендл pwm. * @param _val_ - значение, которое нужно записать в Compare. */ #define PWM_Get_Compare1(_hpwm_) __HAL_TIM_GET_COMPARE(&((_hpwm_)->stim.htim), (_hpwm_)->PWM_Channel1) #define PWM_Get_Compare2(_hpwm_) __HAL_TIM_GET_COMPARE(&((_hpwm_)->stim.htim), (_hpwm_)->PWM_Channel2) /** * @brief Set PWM Duty on corresponding channel. * @param _hpwm_ - указатель на хендл pwm. * @param _val_ - значение, которое нужно записать в Compare. */ #define PWM_Set_Compare1(_hpwm_, _val_) __HAL_TIM_SET_COMPARE(&((_hpwm_)->stim.htim), (_hpwm_)->PWM_Channel1, (_val_)) #define PWM_Set_Compare2(_hpwm_, _val_) __HAL_TIM_SET_COMPARE(&((_hpwm_)->stim.htim), (_hpwm_)->PWM_Channel2, (_val_)) /** * @brief Set PWM Duty From PWM_Value Percent * @param _hpwm_ - указатель на хендл pwm. * @param _channel_ - канал для выставления скважности. * @param _ind_ - номер элемента из таблицы скважностей. */ #define PWM_Set_Duty_From_Percent(_hpwm_, _channel_) __HAL_TIM_SET_COMPARE(&((_hpwm_)->stim.htim), _channel_, ((_hpwm_)->PWM_Value/100)*(PWM_Get_Autoreload(_hpwm_)+1)) /** * @brief Set PWM Duty From table * @param _hpwm_ - указатель на хендл pwm. * @param _channel_ - канал для выставления скважности. * @param _ind_ - номер элемента из таблицы скважностей. */ #define PWM_Set_Duty_From_Table(_hpwm_, _ind_) (PWM_Set_Compare1(_hpwm_, (PWM_Get_Table_Element_Unsigned((_hpwm_), (_ind_))+1))) /** * @brief Set PWM Duty From table * @param _hpwm_ - указатель на хендл pwm. * @param _channel_ - канал для выставления скважности. * @param _ind_ - номер элемента из таблицы скважностей. */ #define PWM_Set_SlaveDuty_From_Table(_hpwm_, _ind_) (PWM_Set_Compare1(_hpwm_, (PWM_Get_Table_Element_Unsigned((_hpwm_)->hMasterPWM, (_ind_))+1))) // MODE DEFINES #define PWM_DC_MODE_Pos (0) #define PWM_CH_MODE_Pos (1) #define PWM_PHASE_MODE_Pos (2) #define PWM_DC_MODE (1<<(PWM_DC_MODE_Pos)) // 0 - set pwm duty from table with PWM_Value period, 1 - set pwm duty PWM_Value (in percent) #define PWM_CH_MODE (1<<(PWM_CH_MODE_Pos)) // DC MODE: 0 - pwm on channel 1, 1 - pwm on channel 2 // TABLE MODE: 0 - signed mode, 1 - unsigned mode #define PWM_PHASE_MODE (1<<(PWM_PHASE_MODE_Pos)) #define PWM_Get_Mode(_hpwm_, _mode_) ((_hpwm_)->sPWM_Mode&(_mode_)) /* Structure for PWM modes */ typedef enum { PWM_TABLE_UNSIGN = 0, /* set pwm duty from table with PWM_Value period */ PWM_TABLE_SIGN = PWM_CH_MODE, /* set pwm duty from table with PWM_Value period on two channels (positive and negative halfes) */ PWM_DC_POS = PWM_DC_MODE, /* set pwm duty PWM_Value (in percent) on first channel */ PWM_DC_NEG = PWM_DC_MODE|PWM_CH_MODE, /* set pwm duty PWM_Value (in percent) on second channel */ PWM_PHASE_UNSIGN = PWM_PHASE_MODE, /* set pwm table duty on three pins, with requested shift */ PWM_PHASE_SIGN = PWM_CH_MODE|PWM_PHASE_MODE, /* set pwm table duty on six pins (two pins = one phase (positive and negative halfes)) */ }PWM_ModeTypeDef; /** * @brief Handle for PWM. * @note Prefixes: h - handle, s - settings, f - flag */ typedef struct // PWM_HandleTypeDef { /* PWM VARIABLES */ PWM_ModeTypeDef sPWM_Mode; /* PWM Mode: 0 - DC mode, 1 - Table mode */ float PWM_Value; /* DC mode: PWM duty, Table mode: frequency*/ uint32_t PWM_MinPulseDur; /* minimum pulse duration for PWM in us*/ uint32_t PWM_DeadTime; /* dead-Time between switches half waves (channels) in us */ /* SETTINGS FOR TIMER */ TIM_SettingsTypeDef stim; /* settings for TIM */ TIM_OC_InitTypeDef sConfigOC; /* settings for oc channel */ unsigned fActiveChannel; /* flag for active oc channel: 0 - first channel, 1 - second channel */ uint16_t PWM_Channel1; /* instance of first channel */ uint16_t PWM_Channel2; /* instance of second channel */ /* VARIABLES FOR TABLE DUTY PARAMETERS */ uint32_t *pDuty_Table_Origin; /* pointer to table of pwm duties */ uint32_t Duty_Table_Size; /* size of duty table */ float Duty_Table_Ind; /* current ind of duty table */ float Duty_Table_Scale; /* scale for TIM ARR register */ /* SETTIGNS FOR PWM OUTPUT */ GPIO_TypeDef *GPIOx; /* GPIO port for PWM output */ uint32_t GPIO_PIN_X1; /* GPIO pin for PWM output */ uint32_t GPIO_PIN_X2; /* GPIO pin for PWM output (second half wave) */ /* SLAVES PWM */ void *hpwm2; void *hpwm3; }PWM_HandleTypeDef; extern PWM_HandleTypeDef hpwm1; /** * @brief Handle for Slave PWM. * @note Prefixes: h - handle, s - settings, f - flag */ typedef struct // PWM_SlaveHandleTypeDef { /* MASTER PWM*/ PWM_HandleTypeDef *hMasterPWM; /* master pwm handle */ /* SETTINGS FOR TIMER */ TIM_SettingsTypeDef stim; /* slave tim handle */ unsigned fActiveChannel; /* flag for active oc channel: 0 - first channel, 1 - second channel */ uint16_t PWM_Channel1; /* instance of first channel */ uint16_t PWM_Channel2; /* instance of second channel */ /* VARIABLES FOR TABLE DUTY PARAMETERS */ float Duty_Table_Ind; /* current ind of duty table */ float Duty_Shift_Ratio; /* Ratio of table shift: 0.5 shift - shift = Table_Size/2 */ /* SETTIGNS FOR PWM OUTPUT */ GPIO_TypeDef *GPIOx; /* GPIO port for PWM output */ uint32_t GPIO_PIN_X1; /* GPIO pin for PWM output */ uint32_t GPIO_PIN_X2; /* GPIO pin for PWM output (second half wave) */ }PWM_SlaveHandleTypeDef; extern PWM_SlaveHandleTypeDef hpwm2; extern PWM_SlaveHandleTypeDef hpwm3; //--------------------------------PWM FUNCTIONS---------------------------------- /** * @brief reInitialization of PWM TIM. * @param hpwm - указатель на хендл ШИМ. * @note Перенастраивает таймер согласно принятным настройкам в pwm_ctrl. */ void PWM_Sine_ReInit(PWM_HandleTypeDef *hpwm); /** * @brief Initialization of Slave PWM TIM. * @param hspwm - указатель на хендл слейв ШИМ. * @note Вызывает функции инициализации и включения слейв ШИМ. */ void PWM_SlavePhase_Init(PWM_SlaveHandleTypeDef *hspwm); /** * @brief reInitialization of Slave PWM TIM. * @param hspwm - указатель на хендл слейв ШИМ. * @note Перенастраивает таймер согласно принятным настройкам в pwm_ctrl. */ void PWM_SlavePhase_reInit(PWM_SlaveHandleTypeDef *hspwm); /** * @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); /** * @brief Calc and update new Duty Table Scale. * @param hpwm - указатель на хендл ШИМ. * @note Используется, когда изменяется значение регистра ARR. */ void PWM_Update_DutyTableScale(PWM_HandleTypeDef *hpwm); //---------------------this called from TIM_PWM_Handler()------------------------ // MASTER PWM FUNCTIONS /** * @brief PWM Handler. * @param hpwm - указатель на хендл ШИМ. * @note Управляет скважность ШИМ в режиме PWM_TABLE. * @note This called from TIM_PWM_Handler */ void PWM_Handler(PWM_HandleTypeDef *hpwm); /** * @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); /** * @brief Create Dead Time when switches channels. * @param hpwm - указатель на хендл ШИМ. * @param LocalDeadTimeCnt - указатель на переменную для отсчитывания дедтайма. * @param LocalActiveChannel - указатель на переменную для отслеживания смены канала. */ void PWM_CreateDeadTime(PWM_HandleTypeDef *hpwm, float *LocalDeadTimeCnt, unsigned *LocalActiveChannel); // SLAVE PWM FUNCTIONS /** * @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); /** * @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); /** * @brief Check is all Slave channels works properly. * @param hspwm - указатель на хендл слейв ШИМ. * @note Проверка работает ли только один из каналов, и проверка чтобы CCRx <= ARR * @note В мастере проверка происходит напрямую в PWM_Handler. */ void PWM_SlavePhase_Check_Channels(PWM_SlaveHandleTypeDef *hspwm); /** * @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); //---------------------this called from TIM_CTRL_Handler()----------------------- /** * @brief Update PWM parameters. * @param hpwm - указатель на хендл ШИМ. * @note Проверка надо ли обновлять параметры ШИМ, и если надо - обновляет их. * @note This called from TIM_CTRL_Handler */ void Update_Params_For_PWM(PWM_HandleTypeDef *hpwm); //---------------------------this called from main()----------------------------- /** * @brief First set up of PWM Two Channel. * @note Первый инит ШИМ. Заполняет структуры и инициализирует таймер для генерации синуоидального ШИМ. * Скважность ШИМ меняется по закону синусоиды, каждый канал генерирует свой полупериод синуса (от -1 до 0 И от 0 до 1) * ШИМ генерируется на одном канале. * @note This called from main OR by setted coil */ void PWM_Sine_FirstInit(void); #endif // __PWM_H_