/**
* @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 *********************************/