/** * @file MOTOR_STEP_O_ATY.c * * @param Project DEVICE_GENERAL_ATY_LIB * * @author ATY * * @copyright * - Copyright 2017 - 2026 MZ-ATY * - This code follows: * - MZ-ATY Various Contents Joint Statement - * * https://mengze.top/MZ-ATY_VCJS * - CC 4.0 BY-NC-SA - * * https://creativecommons.org/licenses/by-nc-sa/4.0/ * - Your use will be deemed to have accepted the terms of this statement. * * @brief functions of open loop stepper motor control for C platform * * @note Slave Mode: Disable * Trigger Source: Disable * Clock Source: Internal Clock * Channel2: PWM Generation CH2 * Prescaler: 71 * Counter Mode: Up * Counter Period: 999 * Internal Clock Division: No Division * auto-reload preload: Disable * Master/Slave Mode (MSM bit): Disable * Trigger Event Selection: Update Event * PWM Generation Channel 2 Mode: PWM mode 2 * Pulse: 499 * Output compare preload: Enable * Fast Mode: Disable * CH Polarity: High * CH Idle State: Reset * * htim1.Init.Prescaler = 71; * htim1.Init.CounterMode = TIM_COUNTERMODE_UP; * htim1.Init.Period = 999; * htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; * htim1.Init.RepetitionCounter = 0; * htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; * sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; * sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; * sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; * sConfigOC.OCMode = TIM_OCMODE_PWM2; * sConfigOC.Pulse = 499; * sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; * sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; * sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; * sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; * sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; * htim2.Init.Prescaler = 0; * htim2.Init.CounterMode = TIM_COUNTERMODE_UP; * htim2.Init.Period = 65535; * htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; * htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; * sSlaveConfig.SlaveMode = TIM_SLAVEMODE_GATED; * sSlaveConfig.InputTrigger = TIM_TS_ITR0; * sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; * sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; * * @version * - 1_00_260109 > ATY * -# Preliminary version ******************************************************************************** */ #ifndef __MOTOR_STEP_O_ATY_C #define __MOTOR_STEP_O_ATY_C #include "MOTOR_STEP_O_ATY.h" #define MOTOR_STEP_O_ATY_TAG "\r\n[MOTOR_STEP_O_ATY] " /******************************* For user *************************************/ /******************************************************************************/ /** * @brief open loop stepper motor control * * @param dev * @param mode * @param enable * @param direction * @param stepCount * @param frequency * @param dutyCycle * @param speed * @return uint8_t 0: no update, 1: update, only for register update, en and dir is hardware * @note - Frequency and speed are mutually exclusive set, when set one, another * is auto calculate and update, speed has higher priority. * - When use speed, dutyCycle will set to 50% automatically. * - This function based on diff input and dev registers, so do not forget * update input registers back after update, like MSO_1_ValueUpdateBack(). */ uint8_t MSO_Cycle(struct MOTOR_STEP_O_ATY_Dev* dev, uint8_t mode, uint8_t enable, uint8_t direction, uint16_t stepCount, float frequency, float dutyCycle, float speed){ uint8_t regUpdateFlag = 0; if(mode != dev->mode){ dev->mode = mode; regUpdateFlag = 1; } if(enable != dev->enable){ dev->enable = enable; dev->enSet(dev->enable); if(regUpdateFlag == 0) regUpdateFlag = 2; } if(direction != dev->direction){ dev->direction = direction; dev->dirSet(dev->direction); if(regUpdateFlag == 0) regUpdateFlag = 2; } if(stepCount != dev->stepCount){ dev->stepCount = stepCount; if(regUpdateFlag == 0) regUpdateFlag = 2; if(dev->mode == MOTOR_OPEN_MODE_COUNT) regUpdateFlag = 1; } if(speed != dev->speed){ dev->speed = speed; dev->frequency = (dev->speed * (dev->fullSteps * dev->microstepping) / 60.0); dev->dutyCycle = 50.0; if(regUpdateFlag == 0) regUpdateFlag = 2; if(dev->mode == MOTOR_OPEN_MODE_NOCOUNT || (dev->mode == MOTOR_OPEN_MODE_COUNT && dev->stepCount == 1)) regUpdateFlag = 1; } else if(frequency != dev->frequency || dutyCycle != dev->dutyCycle){ dev->frequency = frequency; dev->dutyCycle = dutyCycle; if(dev->dutyCycle < 0) dev->dutyCycle = 0; else if(dev->dutyCycle > 100) dev->dutyCycle = 100; dev->speed = (dev->frequency * 60.0 / (dev->fullSteps * dev->microstepping)); if(regUpdateFlag == 0) regUpdateFlag = 2; if(dev->mode == MOTOR_OPEN_MODE_NOCOUNT || (dev->mode == MOTOR_OPEN_MODE_COUNT && dev->stepCount == 1)) regUpdateFlag = 1; } if(regUpdateFlag == 1 && dev->mode == MOTOR_OPEN_MODE_COUNT){ dev->pwmSetCount(dev->frequency, dev->dutyCycle, dev->stepCount); } else if(regUpdateFlag == 1 && dev->mode == MOTOR_OPEN_MODE_NOCOUNT){ dev->pwmSet(dev->frequency, dev->dutyCycle); } return regUpdateFlag; } #endif /* __MOTOR_STEP_O_ATY_C */ /************************************ etc *************************************/ /* init #define MS_1_TIM htim1 #define MS_1_TIM_CHANNEL TIM_CHANNEL_2 #define MS_1_TIM_IT_CC TIM_IT_CC2 #define MS_1_COUNT_TIM htim2 // MOTOR Open ------------------------------------------------------------------ #include "MOTOR_STEP_O_ATY.h" uint8_t MSO_1_EnSet(uint8_t en){ HAL_GPIO_WritePin(MS_EN_GPIO_Port, MS_EN_Pin, (en == 0) ? GPIO_PIN_SET : GPIO_PIN_RESET); return __ATY_OK; } uint8_t MSO_1_DirSet(uint8_t dir){ HAL_GPIO_WritePin(MS_DIRO_GPIO_Port, MS_DIRO_Pin, (dir == __ATY_PN_P) ? GPIO_PIN_SET : GPIO_PIN_RESET); return __ATY_OK; } void MSO_1_PWM_NoCount(float freq, float dutycycle){ uint32_t ticksPeriod = 1000000U / freq; uint32_t ticksPulse = ticksPeriod * (100.0 - dutycycle) / 100.0; HAL_TIM_PWM_Stop(&MS_1_TIM, MS_1_TIM_CHANNEL); __HAL_TIM_SET_COUNTER(&MS_1_TIM, 0); __HAL_TIM_SET_AUTORELOAD(&MS_1_TIM, ticksPeriod - 1); __HAL_TIM_SET_COMPARE(&MS_1_TIM, MS_1_TIM_CHANNEL, ticksPulse - 1); HAL_TIM_PWM_Start(&MS_1_TIM, MS_1_TIM_CHANNEL); } void MSO_1_PWM_Count(float freq, float dutycycle, uint16_t step){ uint32_t ticksPeriod = 1000000U / freq; uint32_t ticksPulse = ticksPeriod * (100.0 - dutycycle) / 100.0; HAL_TIM_PWM_Stop(&MS_1_TIM, MS_1_TIM_CHANNEL); HAL_TIM_Base_Stop_IT(&MS_1_COUNT_TIM); __HAL_TIM_SET_COUNTER(&MS_1_TIM, 0); // Set 1 to make sure the system can generate one pulse __HAL_TIM_SET_COUNTER(&MS_1_COUNT_TIM, 1); if(step != 0){ // init counter 1, then do not need -1 __HAL_TIM_SET_AUTORELOAD(&MS_1_COUNT_TIM, step); __HAL_TIM_SET_AUTORELOAD(&MS_1_TIM, ticksPeriod - 1); __HAL_TIM_SET_COMPARE(&MS_1_TIM, MS_1_TIM_CHANNEL, ticksPulse - 1); HAL_TIM_Base_Start_IT(&MS_1_COUNT_TIM); HAL_TIM_PWM_Start(&MS_1_TIM, MS_1_TIM_CHANNEL); } } struct MOTOR_STEP_O_ATY_Dev MOTOR_STEP_O_ATY_Dev_1 = { .enSet = MSO_1_EnSet, .dirSet = MSO_1_DirSet, .pwmSet = MSO_1_PWM_NoCount, .pwmSetCount = MSO_1_PWM_Count, .mode = 0xFF, .enable = 0xFF, .direction = 0xFF, .stepCount = 0xFFFF, .frequency = -1.0, .dutyCycle = -1.0, .speed = -1.0, .fullSteps = 200, .microstepping = 8, .lock = __ATY_UNLOCKED }; void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim){ if(htim == &htim4){ UserTimerLoop_Cycle1ms(&HW_TIMER_ATY_Dev_4); } if((uint8_t)RGF_MOTOR_MODE == 0 && htim == &MS_1_COUNT_TIM){ HAL_TIM_PWM_Stop(&MS_1_TIM, MS_1_TIM_CHANNEL); HAL_TIM_Base_Stop_IT(&MS_1_COUNT_TIM); RGF_MOTOR_STEP_COUNT = 0; MOTOR_STEP_O_ATY_Dev_1.stepCount = 0; } } void MSO_1_ValueUpdateBack(struct MOTOR_STEP_O_ATY_Dev* dev){ RGF_MOTOR_MODE = dev->mode; RGF_MOTOR_ENABLE = dev->enable; RGF_MOTOR_DIRECTION = dev->direction; // RGF_MOTOR_STEP_COUNT = dev->stepCount; RGF_MOTOR_FREQUENCY = dev->frequency; RGF_MOTOR_DUTY_CYCLE = dev->dutyCycle; RGF_MOTOR_SPEED = dev->speed; } void MSO_1_Init(void){ RGF_MOTOR_MODE = MOTOR_OPEN_MODE_COUNT; RGF_MOTOR_ENABLE = 1; RGF_MOTOR_DIRECTION = __ATY_PN_P; RGF_MOTOR_STEP_COUNT = 10000; RGF_MOTOR_FREQUENCY = (1600.0 / 60.0); RGF_MOTOR_DUTY_CYCLE = 50.0; RGF_MOTOR_SPEED = 200.0; // Prevent from getting into an interruption from the very beginning __HAL_TIM_CLEAR_FLAG(&MS_1_COUNT_TIM, TIM_FLAG_UPDATE); } */ /* use MSO_1_Init(); // 100ms cycle if(MSO_Cycle(&MOTOR_STEP_O_ATY_Dev_1, (uint8_t)RGF_MOTOR_MODE, (uint8_t)RGF_MOTOR_ENABLE, (uint8_t)RGF_MOTOR_DIRECTION, (uint16_t)RGF_MOTOR_STEP_COUNT, RGF_MOTOR_FREQUENCY, RGF_MOTOR_DUTY_CYCLE, RGF_MOTOR_SPEED) != 0){ MSO_1_ValueUpdateBack(&MOTOR_STEP_O_ATY_Dev_1); } */ /******************************************************************************/ /******************************** End Of File *********************************/