ST Expansion SW Team / X_NUCLEO_IHM14A1

Dependencies:   ST_INTERFACES

Dependents:   HelloWorld_IHM14A1

Fork of X_NUCLEO_IHM14A1 by Davide Aliprandi

Components/STSPIN820/STSPIN820.cpp

Committer:
Davidroid
Date:
2018-09-27
Revision:
2:4fd08b67958c
Parent:
1:bc265521eb00

File content as of revision 2:4fd08b67958c:

/**
 *******************************************************************************
 * @file    STSPIN820.cpp
 * @author  STM
 * @version V1.0.0
 * @date    August 7th, 2017
 * @brief   STSPIN820 driver (fully integrated microstepping motor driver).
 * @note    (C) COPYRIGHT 2017 STMicroelectronics
 *******************************************************************************
 * @attention
 *
 * <h2><center>&copy; COPYRIGHT(c) 2017 STMicroelectronics</center></h2>
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *   1. Redistributions of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright notice,
 *      this list of conditions and the following disclaimer in the documentation
 *      and/or other materials provided with the distribution.
 *   3. Neither the name of STMicroelectronics nor the names of its contributors
 *      may be used to endorse or promote products derived from this software
 *      without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *******************************************************************************
 */


/* Generated with STM32CubeTOO -----------------------------------------------*/


/* Revision ------------------------------------------------------------------*/
/*
    Repository:       http://svn.x-nucleodev.codex.cro.st.com/svnroot/X-NucleoDev
    Branch/Trunk/Tag: trunk
    Based on:         X-CUBE-SPN14/trunk/Drivers/BSP/Components/STSPIN820/STSPIN820.c
    Revision:         0
*/


/* Includes ------------------------------------------------------------------*/

#include "STSPIN820.h"


/* Variables  ----------------------------------------------------------------*/

/* Number of devices. */
uint8_t STSPIN820::number_of_devices = 0;


/* Private function prototypes -----------------------------------------------*/

/** @defgroup STSPIN820_Private_Functions STSPIN820 Private Functions
  * @{
  */  
/* Methods -------------------------------------------------------------------*/

/** @defgroup STSPIN820_Exported_Variables STSPIN820 Exported Variables
  * @{
  */

/** @defgroup STSPIN820_Library_Functions STSPIN820 Library Functions
  * @{
  */

/**********************************************************
 * @brief Starts the STSPIN820 library
 * @param  init Initialization structure.
 * @retval COMPONENT_OK in case of success.
 **********************************************************/
status_t STSPIN820::STSPIN820_Init(void *init)
{
  /* Initialise the GPIOs */
  STSPIN820_GpioInit();

  /* Initialise the timer used for the step clock and ------------------------*/
  /* the PWM for the reference voltage generation ----------------------------*/
  STSPIN820_TimStckInit();
  STSPIN820_PwmRefInit();

  if (init == 0)
  {
    /* Set all context variables to the predefined values */
    /* from STSPIN820_config.h */
    STSPIN820_SetDeviceParamsToPredefinedValues();
  }
  else
  {
    STSPIN820_SetDeviceParamsToGivenValues((STSPIN820_init_t*) init);
  }

  return COMPONENT_OK;
}

/**********************************************************
 * @brief Read id
 * @param id pointer to the identifier to be read.
 * @retval COMPONENT_OK in case of success.
 **********************************************************/
status_t STSPIN820::STSPIN820_ReadId(uint8_t *id)
{
  *id = device_instance;

  return COMPONENT_OK;
}

/**********************************************************
 * @brief Attach a user callback to the error Handler.
 * The call back will be then called each time the library 
 * detects an error
 * @param[in] callback Name of the callback to attach 
 * to the error Hanlder
 * @retval None
 **********************************************************/
void STSPIN820::STSPIN820_AttachErrorHandler(void (*callback)(uint16_t error))
{
  error_handler_callback = (void (*)(uint16_t error))callback;
}

/**********************************************************
 * @brief Attach a user callback to the flag Interrupt
 * The call back will be then called each time the status 
 * flag pin will be pulled down due to the occurrence of 
 * a programmed alarms ( OCD, thermal pre-warning or 
 * shutdown, UVLO, wrong command, non-performable command)
 * @param[in] callback Name of the callback to attach 
 * to the Flag Interrupt
 * @retval None
 **********************************************************/
void STSPIN820::STSPIN820_AttachFlagInterrupt(void (*callback)(void))
{
  flag_interrupt_callback = (void (*)(void))callback;
}

/**********************************************************
 * @brief Check if STSPIN820 has a fault by reading EN pin position.
 * @retval One if STSPIN820 has EN pin down, otherwise zero
 **********************************************************/
uint8_t STSPIN820::STSPIN820_CheckStatusHw(void)
{
  if(!STSPIN820_EN_FAULT_PIN_GetState())
  {
    return 0x01;
  }
  else
  {
    return 0x00;
  }
}

/**********************************************************
 * @brief Disable the power bridges (leave the output bridges HiZ)
 * @retval None
 **********************************************************/
void STSPIN820::STSPIN820_Disable(void)
{
  STSPIN820_Disable_Power_Bridges();
}

/**********************************************************
 * @brief Enable the power bridges
 * @retval None
 **********************************************************/
void STSPIN820::STSPIN820_Enable(void)
{
  STSPIN820_Enable_Power_Bridges();
}

/**********************************************************
 * @brief Error handler which calls the user callback (if defined)
 * @param[in] error Number of the error
 * @retval None
 **********************************************************/
void STSPIN820::STSPIN820_ErrorHandler(uint16_t error)
{
  if (error_handler_callback != 0)
  {
    (void) error_handler_callback(error);
  }
  else   
  {
    while(1)
    {
      /* Infinite loop */
    }
  }
}

/**********************************************************
 * @brief Exit STSPIN820 device from standby (low power consumption)
 * @retval None
 **********************************************************/
void STSPIN820::STSPIN820_ExitDeviceFromStandby(void)
{
  uint32_t sequencerPosition = device_prm.sequencerPosition;
  
  /* Exit standby and set step mode */
  /* Disable step clock */
  if (STSPIN820_TimStckStop(&toggle_odd) == 0)
  {
    STSPIN820_ErrorHandler(STSPIN820_ERROR_STEP_CLOCK);
  }

  /* Let the PWM REF and bridges enabled at least for DISABLE_DELAY time */
  /* after the last step clock rising edge triggering the last step */
  STSPIN820_Delay(DISABLE_DELAY);
    /* Set reference voltage to 0 */
  STSPIN820_SetTorque( CURRENT_TORQUE, 0);

  /* Disable power bridges */
  STSPIN820_Disable_Power_Bridges();
  
  device_prm.commandExecuted = NO_CMD;
  device_prm.stepsToTake = 0;  
  device_prm.speed = 0;

  /* Reset the microstepping sequencer position */
  device_prm.sequencerPosition = 0;

  /* Reset current and mark positions */
  device_prm.currentPosition = 0; 
  device_prm.markPosition = 0;
  
  STSPIN820_SetStepMode(device_prm.stepMode);
  STSPIN820_ReleaseReset();
  STSPIN820_Delay(AFTER_STANDBY_EXIT_DEAD_TIME);
  
  STSPIN820_SetHome();
  STSPIN820_SetMark();
  
  if (device_prm.sequencerPosition != 0)
  {
    /* Set direction to FORWARD to ensure the HW sequencer is increased at */
    /* each step clock rising edge */
    STSPIN820_SetDirection(FORWARD);
    /* Going out of standby */
    device_prm.motionState = STANDBYTOINACTIVE;
    /* Initialize the step clock timer */
    STSPIN820_TimStckInit();
    /* Program the step clock */    
    STSPIN820_TimStckCompareInit();
    STSPIN820_TimStckSetFreq(STSPIN820_MAX_STCK_FREQ);
    toggle_odd = 0;
    STSPIN820_TimStckStart();
    while (device_prm.sequencerPosition != 0);
    while (toggle_odd!=0);
    device_prm.sequencerPosition = sequencerPosition;    
  }
  
  device_prm.motionState = INACTIVE;
}

/**********************************************************
 * @brief Return the acceleration of the specified device
 * @retval Acceleration in pps^2
 **********************************************************/
uint16_t STSPIN820::STSPIN820_GetAcceleration(void)
{
  return (device_prm.acceleration);
}            

/**********************************************************
 * @brief Return the current speed of the specified device
 * @retval Speed in pps
 **********************************************************/
uint16_t STSPIN820::STSPIN820_GetCurrentSpeed(void)
{
  return device_prm.speed;
}

/**********************************************************
 * @brief Return the decay mode of the specified device
 * @retval Decay Mode State (SLOW or MIXED)
 **********************************************************/
motor_decay_mode_t STSPIN820::STSPIN820_GetDecayMode(void)
{
  motor_decay_mode_t status;
  if (STSPIN820_GetDecayGpio() != 0) 
  {
    status = SLOW_DECAY;
  }
  else
  {
    status = MIXED_DECAY;
  }
  
  return status;
}

/**********************************************************
 * @brief Return the deceleration of the specified device
 * @retval Deceleration in pps^2
 **********************************************************/
uint16_t STSPIN820::STSPIN820_GetDeceleration(void)
{
  return (device_prm.deceleration);
}          

/**********************************************************
 * @brief Return the device state
 * @retval State (ACCELERATING, DECELERATING, STEADY or INACTIVE)
 **********************************************************/
motor_state_t STSPIN820::STSPIN820_GetDeviceState(void)
{
  return device_prm.motionState;
}

/**********************************************************
 * @brief Get the motor current direction
 * @retval direction
 **********************************************************/
motor_direction_t STSPIN820::STSPIN820_GetDirection(void)
{
  return device_prm.direction;
}

/**********************************************************
 * @brief Return the FW version of the library
 * @retval Stspin220_FW_VERSION
 **********************************************************/
uint32_t STSPIN820::STSPIN820_GetFwVersion(void)
{
  return (STSPIN820_FW_VERSION);
}

/**********************************************************
 * @brief Return the mark position of the specified device
 * @retval mark position value
 **********************************************************/
int32_t STSPIN820::STSPIN820_GetMark(void)
{
  return device_prm.markPosition;
}

/**********************************************************
 * @brief Return the max speed of the specified device
 * @retval maxSpeed in pps
 **********************************************************/
uint16_t STSPIN820::STSPIN820_GetMaxSpeed(void)
{
  return (device_prm.maxSpeed);
}

/**********************************************************
 * @brief Return the min speed of the specified device
 * @retval minSpeed in pps
 **********************************************************/
uint16_t STSPIN820::STSPIN820_GetMinSpeed(void)
{
  return (device_prm.minSpeed);
}                                                     

/**********************************************************
 * @brief  Returns the number of devices
 * @retval number of devices
 **********************************************************/
uint8_t STSPIN820::STSPIN820_GetNbDevices(void)
{
  return (number_of_devices);
}

/**********************************************************
 * @brief Return the current position value of the specified device
 * @retval current position value
 **********************************************************/
int32_t STSPIN820::STSPIN820_GetPosition(void)
{
  return device_prm.currentPosition;
}

/**********************************************************
 * @brief Get the motor step mode
 * @retval step mode
 **********************************************************/
motor_step_mode_t STSPIN820::STSPIN820_GetStepMode(void)
{
  return device_prm.stepMode;
}

/**********************************************************
 * @brief Get the selected stop mode
 * @retval the selected stop mode
 **********************************************************/
motor_stop_mode_t STSPIN820::STSPIN820_GetStopMode(void)
{
  return device_prm.stopMode;
}

/**********************************************************
 * @brief Get the torque of the specified device
 * @param[in] torqueMode torque mode
 * @retval the torqueValue in % (from 0 to 100)
 * @note
 **********************************************************/
uint8_t STSPIN820::STSPIN820_GetTorque(motor_torque_mode_t torqueMode)
{
  uint8_t torqueValue = 0;
  switch(torqueMode)
  {
    case ACC_TORQUE:
      torqueValue = device_prm.accelTorque;
      break;
    case DEC_TORQUE:
      torqueValue = device_prm.decelTorque;
      break;
    case RUN_TORQUE:
      torqueValue = device_prm.runTorque;
      break;
    case HOLD_TORQUE:
      torqueValue = device_prm.holdTorque;
      break;
    case CURRENT_TORQUE:
      torqueValue = device_prm.currentTorque;
      break;
    default:
      break;
  }
  return torqueValue;
}

/**********************************************************
 * @brief Get the torque boost feature status
 * @retval TRUE if enabled, FALSE if disabled
 **********************************************************/
bool STSPIN820::STSPIN820_GetTorqueBoostEnable(void)
{
  return device_prm.torqueBoostEnable;
}

/**********************************************************
 * @brief Get the torque boost threshold
 * @param[in]  (from 0 to MAX_NUMBER_OF_DEVICES - 1)
 * @retval the torque boost threshold above which the step mode is
 * changed to full step
 **********************************************************/
uint16_t STSPIN820::STSPIN820_GetTorqueBoostThreshold(void)
{
  return device_prm.torqueBoostSpeedThreshold;
}

/**********************************************************
 * @brief Request the motor to move to the home position (ABS_POSITION = 0)
 * @retval None
 **********************************************************/
void STSPIN820::STSPIN820_GoHome(void)
{
  STSPIN820_GoTo(0);
} 
  
/**********************************************************
 * @brief Request the motor to move to the mark position 
 * @retval None
 **********************************************************/
void STSPIN820::STSPIN820_GoMark(void)
{
    STSPIN820_GoTo(device_prm.markPosition);
}

/**********************************************************
 * @brief Request the motor to move to the specified position 
 * @param[in] targetPosition absolute position in steps
 * @retval None 
 * @note The position is at the resolution corresponding to the
 * selected step mode.
 * STEP_MODE_FULL                   : Full step
 * STEP_MODE_HALF                   : 1/2 step
 * STEP_MODE_1_4                    : 1/4 step
 * STEP_MODE_1_8                    : 1/8 step
 * STEP_MODE_1_16                   : 1/16 step
 * STEP_MODE_1_32                   : 1/32 step
 * STEP_MODE_1_128                  : 1/128 step
 * STEP_MODE_1_256                  : 1/256 step
 * @note The 1/64 step mode is not allowed
 **********************************************************/
void STSPIN820::STSPIN820_GoTo(int32_t targetPosition)
{
  motor_direction_t direction;
  
  /* Exit from standby if needed */
  if (device_prm.motionState == STANDBY)
  {
    STSPIN820_ExitDeviceFromStandby();
  }
  /* Deactivate motor if needed */
  else if (device_prm.motionState != INACTIVE)
  { 
    STSPIN820_HardHiZ();
  }
  
  if (targetPosition > device_prm.currentPosition)
  {
    device_prm.stepsToTake = targetPosition -\
                                      device_prm.currentPosition;
    if (device_prm.stepsToTake < (STSPIN820_POSITION_RANGE>>1))
    {
      direction = FORWARD;
    }
    else
    {
      direction = BACKWARD;
      device_prm.stepsToTake = STSPIN820_POSITION_RANGE -\
                                        device_prm.stepsToTake;
    }
  }
  else
  {
    device_prm.stepsToTake = device_prm.currentPosition -\
                                      targetPosition;
    if (device_prm.stepsToTake < (STSPIN820_POSITION_RANGE>>1))
    {
      direction = BACKWARD;
    }
    else
    {
      direction = FORWARD; 
      device_prm.stepsToTake = STSPIN820_POSITION_RANGE -\
                                        device_prm.stepsToTake;
    }
  }
  
  if (device_prm.stepsToTake != 0) 
  {
    device_prm.commandExecuted = MOVE_CMD;
    
    /* Direction setup */
    STSPIN820_SetDirection(direction);
    
    STSPIN820_ComputeSpeedProfile(device_prm.stepsToTake);
    
    /* Motor activation */
    STSPIN820_StartMovement();
  }
}

/**********************************************************
 * @brief Move the motor to the absolute position
 * @param[in] direction FORWARD or BACKWARD
 * @param[in] targetPosition 32 bit signed value position
 * @retval None
 * @note The position is at the resolution corresponding to the
 * selected step mode.
 * STEP_MODE_FULL                   : step
 * STEP_MODE_HALF                   : 1/2 step
 * STEP_MODE_1_4                    : 1/4 step
 * STEP_MODE_1_8                    : 1/8 step
 * STEP_MODE_1_16                   : 1/16 step
 * STEP_MODE_1_32                   : 1/32 step
 * STEP_MODE_1_128                  : 1/128 step
 * STEP_MODE_1_256                  : 1/256 step
 * @note The 1/64 step mode is not allowed
 **********************************************************/
void STSPIN820::STSPIN820_GoToDir(motor_direction_t direction, int32_t targetPosition)
{
  /* Exit from standby if needed */
  if (device_prm.motionState == STANDBY)
  {
    STSPIN820_ExitDeviceFromStandby();
  }
  /* Deactivate motor if needed */
  else if (device_prm.motionState != INACTIVE)
  { 
    STSPIN820_HardHiZ();
  }
  
  if (direction != BACKWARD)
  {
    if (targetPosition > device_prm.currentPosition)
    {
      device_prm.stepsToTake = targetPosition -\
                                        device_prm.currentPosition;
    }
    else
    {
      device_prm.stepsToTake = STSPIN820_POSITION_RANGE +\
                                       (targetPosition -\
                                        device_prm.currentPosition);
    }
  }
  else
  {
    if (targetPosition > device_prm.currentPosition)
    {
      device_prm.stepsToTake = STSPIN820_POSITION_RANGE +\
                                        (device_prm.currentPosition -\
                                         targetPosition);
    }
    else
    {
      device_prm.stepsToTake = device_prm.currentPosition -\
                                        targetPosition;
    }
  }

  if (device_prm.stepsToTake != 0) 
  {
    device_prm.commandExecuted = MOVE_CMD;
    
    /* Direction setup */
    STSPIN820_SetDirection(direction);
    
    STSPIN820_ComputeSpeedProfile(device_prm.stepsToTake);
    
    /* Motor activation */
    STSPIN820_StartMovement();
  }  
}

/**********************************************************
 * @brief  Immediatly stop the motor and disable the power bridge
 * @retval None
 **********************************************************/
void STSPIN820::STSPIN820_HardHiZ(void) 
{
  /* Set inactive state */
  device_prm.motionState = INACTIVE;
  
  /* Disable step clock */
  if (STSPIN820_TimStckStop(&toggle_odd) == 0)
  {
    STSPIN820_ErrorHandler(STSPIN820_ERROR_STEP_CLOCK);
  }

  /* Let the PWM REF and bridges enabled at least for DISABLE_DELAY time */
  /* after the last step clock rising edge triggering the last step */
  STSPIN820_Delay(DISABLE_DELAY);
  
  /* Set reference voltage to 0 */
  STSPIN820_SetTorque(CURRENT_TORQUE, 0);

  /* Disable power bridges */
  STSPIN820_Disable_Power_Bridges();
  
  /* Comeback to nominal step mode */
  if (device_prm.stepModeLatched != device_prm.stepMode)
  {
    motor_step_mode_t StepMode = device_prm.stepModeLatched;
    STSPIN820_SetStepMode(StepMode);
    device_prm.stepMode = device_prm.stepModeLatched;
  }

  device_prm.commandExecuted = NO_CMD;
  device_prm.stepsToTake = 0;  
  device_prm.speed = 0;
}

/**********************************************************
 * @brief  Immediatly stop the motor
 * and either set holding torque when stop mode is HOLD_MODE,
 * or call STSPIN820_HardHiz function when stop mode is HIZ_MODE,
 * or call STSPIN820_PutDeviceInStandby function when stop mode is STANDBY_MODE
 * @retval None
 **********************************************************/
void STSPIN820::STSPIN820_HardStop(void) 
{
  if (device_prm.stopMode == HOLD_MODE)
  {
    /* Set inactive state */
    device_prm.motionState = INACTIVE;

    /* Disable step clock */
    if (STSPIN820_TimStckStop(&toggle_odd) == 0)
    {
      STSPIN820_ErrorHandler(STSPIN820_ERROR_STEP_CLOCK);
    }
    
    /* Set holding torque */
    STSPIN820_ApplyTorque(HOLD_TORQUE);
 
    /* Comeback to nominal step mode */
    if (device_prm.stepModeLatched != device_prm.stepMode)
    {
      motor_step_mode_t StepMode = device_prm.stepModeLatched;
      STSPIN820_SetStepMode(StepMode);
      device_prm.stepMode = device_prm.stepModeLatched;
    }    
    
    device_prm.commandExecuted = NO_CMD;
    device_prm.stepsToTake = 0;  
    device_prm.speed = 0;
  }
  else if (device_prm.stopMode == HIZ_MODE)
  {
    STSPIN820_HardHiZ();
  }
  else if (device_prm.stopMode == STANDBY_MODE)
  {
    STSPIN820_PutDeviceInStandby();
  }
}

/**********************************************************
 * @brief  Moves the motor of the specified number of steps
 * @param[in] direction FORWARD or BACKWARD
 * @param[in] stepCount Number of steps to perform
 * @retval None
 **********************************************************/
void STSPIN820::STSPIN820_Move(motor_direction_t direction, uint32_t stepCount)
{
  /* Exit from standby if needed */
  if (device_prm.motionState == STANDBY)
  {
    STSPIN820_ExitDeviceFromStandby();
  }
  /* Deactivate motor if needed */
  else if (device_prm.motionState != INACTIVE)
  {
    STSPIN820_HardHiZ();
  }
  
  if (stepCount != 0) 
  {
    device_prm.stepsToTake = stepCount;    
    device_prm.commandExecuted = MOVE_CMD;
    
    /* Direction setup */
    STSPIN820_SetDirection(direction);
    
    STSPIN820_ComputeSpeedProfile(stepCount);
    
    /* Motor activation */
    STSPIN820_StartMovement();
  }  
}

/**********************************************************
 * @brief Put STSPIN820 device in standby (low power consumption)
 * @retval None
 **********************************************************/
void STSPIN820::STSPIN820_PutDeviceInStandby(void)
{
  /* Stop movement */
  STSPIN820_HardHiZ();
  
  /* Enter standby */
    STSPIN820_Reset();
  
  device_prm.motionState = STANDBY;
}

/**********************************************************
 * @brief  Runs the motor. It will accelerate from the min 
 * speed up to the max speed by using the device acceleration.
 * @param[in] direction FORWARD or BACKWARD
 * @retval None
 **********************************************************/
void STSPIN820::STSPIN820_Run(motor_direction_t direction)
{
  /* Exit from standby if needed */
  if (device_prm.motionState == STANDBY)
  {
    STSPIN820_ExitDeviceFromStandby();
  }
  /* Deactivate motor if needed */
  else if (device_prm.motionState != INACTIVE)
  {
    STSPIN820_HardHiZ();
  }
  
    /* Direction setup */
    STSPIN820_SetDirection(direction);
    device_prm.commandExecuted = RUN_CMD;
    /* Motor activation */
    STSPIN820_StartMovement(); 
}

/**********************************************************
 * @brief  Changes the acceleration of the specified device
 * @param[in] newAcc New acceleration to apply in pps^2
 * @retval true if the command is successfully executed, else false
 * @note The command is not performed if the device is executing 
 * a MOVE or GOTO command (but it can be used during a RUN command)
 **********************************************************/
bool STSPIN820::STSPIN820_SetAcceleration(uint16_t newAcc)
{
  bool cmdExecuted = FALSE;
  if ((newAcc != 0)&&
      (((device_prm.motionState & INACTIVE) == INACTIVE)||
       (device_prm.commandExecuted == RUN_CMD)))
  {
    device_prm.acceleration = newAcc;
    cmdExecuted = TRUE;
  }    
  return cmdExecuted;
}            

/**********************************************************
 * @brief  Specifies the decay mode 
 * @param[in] decay SLOW_DECAY or MIXED_DECAY
 * @retval true if the command is successfully executed, else false
 **********************************************************/
void STSPIN820::STSPIN820_SetDecayMode(motor_decay_mode_t decay)
{ 
  if (decay == SLOW_DECAY)
  {
    STSPIN820_SetDecayGpio(1);
  }
  else if (decay == MIXED_DECAY)
  {
    STSPIN820_SetDecayGpio(0);
  }
}

/**********************************************************
 * @brief  Changes the deceleration of the specified device
 * @param[in] newDec New deceleration to apply in pps^2
 * @retval true if the command is successfully executed, else false
 * @note The command is not performed if the device is executing 
 * a MOVE or GOTO command (but it can be used during a RUN command)
 **********************************************************/
bool STSPIN820::STSPIN820_SetDeceleration(uint16_t newDec)
{
  bool cmdExecuted = FALSE;
  if ((newDec != 0)&& 
      (((device_prm.motionState & INACTIVE) == INACTIVE)||
       (device_prm.commandExecuted == RUN_CMD)))
  {
    device_prm.deceleration = newDec;
    cmdExecuted = TRUE;
  }      
  return cmdExecuted;
}

/**********************************************************
 * @brief  Specifies the direction 
 * @param[in] dir FORWARD or BACKWARD
 * @note The direction change is applied if the device 
 * is in INACTIVE or STANDBY state or if the device is 
 * executing a run command
 * @retval None
 **********************************************************/
void STSPIN820::STSPIN820_SetDirection(motor_direction_t dir)
{
  if ((device_prm.motionState == INACTIVE)||\
      (device_prm.motionState == STANDBY))
  {
    device_prm.direction = dir;
    STSPIN820_SetDirectionGpio(dir);
  }
  else if ((device_prm.commandExecuted&RUN_CMD)!=0)
  {
    device_prm.commandExecuted = (device_command_t) (device_prm.commandExecuted | STSPIN820_DIR_CHANGE_BIT_MASK);
  }
}

/**********************************************************
 * @brief  Set current position to be the Home position
 * (current position set to 0)
 * @retval None
 **********************************************************/
void STSPIN820::STSPIN820_SetHome(void)
{
  device_prm.currentPosition = 0;
}
 
/**********************************************************
 * @brief  Set current position to be the Mark position 
 * @retval None
 **********************************************************/
void STSPIN820::STSPIN820_SetMark(void)
{
  device_prm.markPosition = device_prm.currentPosition;
}

/**********************************************************
 * @brief  Changes the max speed of the specified device
 * @param[in] newMaxSpeed New max speed  to apply in pps
 * @retval true if the command is successfully executed, else false
 * @note The command is not performed is the device is executing 
 * a MOVE or GOTO command (but it can be used during a RUN command).
 **********************************************************/
bool STSPIN820::STSPIN820_SetMaxSpeed(uint16_t newMaxSpeed)
{
  bool cmdExecuted = FALSE;
  if ((newMaxSpeed >= STSPIN820_MIN_STCK_FREQ)&&\
      ((newMaxSpeed <= STSPIN820_MAX_STCK_FREQ)||\
       ((device_prm.torqueBoostEnable != FALSE)&&\
        ((newMaxSpeed>>STSPIN820_GetStepMode())<= STSPIN820_MAX_STCK_FREQ)))&&\
      (device_prm.minSpeed <= newMaxSpeed) &&\
      (((device_prm.motionState & INACTIVE) == INACTIVE)||\
      (device_prm.commandExecuted == RUN_CMD)))
  {
    device_prm.maxSpeed = newMaxSpeed;
    cmdExecuted = TRUE;
  }
  return cmdExecuted;
}                                                     

/**********************************************************
 * @brief  Changes the min speed of the specified device
 * @param[in] newMinSpeed New min speed  to apply in pps
 * @retval true if the command is successfully executed, else false
 * @note The command is not performed is the device is executing 
 * a MOVE or GOTO command (but it can be used during a RUN command).
 **********************************************************/
bool STSPIN820::STSPIN820_SetMinSpeed(uint16_t newMinSpeed)
{
  bool cmdExecuted = FALSE;
  if ((newMinSpeed >= STSPIN820_MIN_STCK_FREQ)&&
      (newMinSpeed <= STSPIN820_MAX_STCK_FREQ) &&
      (newMinSpeed <= device_prm.maxSpeed) && 
      (((device_prm.motionState & INACTIVE) == INACTIVE)||
       (device_prm.commandExecuted == RUN_CMD)))
  {
    device_prm.minSpeed = newMinSpeed;
    cmdExecuted = TRUE;
  }  
  return cmdExecuted;
}

/**********************************************************
 * @brief  Sets the number of devices to be used 
 * @param[in] nbDevices (from 1 to MAX_NUMBER_OF_DEVICES)
 * @retval TRUE if successfull, FALSE if failure, attempt to set a number of 
 * devices greater than MAX_NUMBER_OF_DEVICES
 **********************************************************/
bool STSPIN820::STSPIN820_SetNbDevices(uint8_t nbDevices)
{
  if (nbDevices <= MAX_NUMBER_OF_DEVICES)
  {
    number_of_devices = nbDevices;
    return TRUE;
  }
  else
  {
    return FALSE;
  }
}

/**********************************************************
 * @brief Set the stepping mode 
 * @param[in] stepMode from full step to 1/256 microstep
 * as specified in enum motor_step_mode_t
 * 1/64 microstep mode not supported by STSPIN820
 * @retval true if the command is successfully executed, else false
 **********************************************************/
bool STSPIN820::STSPIN820_SetStepMode(motor_step_mode_t stepMode)
{
  /* Store step mode */
  device_prm.stepMode = stepMode;
  device_prm.stepModeLatched = stepMode;
  
  /* Set the mode pins to the levels corresponding to the selected step mode */
  switch (stepMode)
  {
    case STEP_MODE_FULL:
      STSPIN820_SetFullStep();
      break;
    case STEP_MODE_HALF:
      STSPIN820_SetModePins(1, 0, 0);
      break;    
    case STEP_MODE_1_4:
      STSPIN820_SetModePins(0, 1, 0);
      break;        
    case STEP_MODE_1_8:
      STSPIN820_SetModePins(1, 1, 0);
      break;
    case STEP_MODE_1_16:
      STSPIN820_SetModePins(0, 0, 1);
      break;   
    case STEP_MODE_1_32:
      STSPIN820_SetModePins(1, 0, 1);
      break;   
    case STEP_MODE_1_128:
      STSPIN820_SetModePins(0, 1, 1);
      break;  
    case STEP_MODE_1_256:
      STSPIN820_SetModePins(1, 1, 1);
      break;
    default:
      return FALSE;
  }

  return TRUE;
  
}

/**********************************************************
 * @brief Select the mode to stop the motor.
 * @param[in] stopMode HOLD_MODE to let power bridge enabled
 * @retval None
 **********************************************************/
void STSPIN820::STSPIN820_SetStopMode(motor_stop_mode_t stopMode)
{
  device_prm.stopMode = stopMode;
}

/**********************************************************
 * @brief Set the torque of the specified device
 * @param[in] torqueMode Torque mode as specified in enum motor_torque_mode_t
 * @param[in] torqueValue in % (from 0 to 100)
 * @retval None
 * @note
 **********************************************************/
void STSPIN820::STSPIN820_SetTorque(motor_torque_mode_t torqueMode, uint8_t torqueValue)
{
  device_prm.updateTorque = TRUE;
  if (torqueValue>100)
  {
    torqueValue = 100;
  }
  switch(torqueMode)
  {
    case ACC_TORQUE:
      device_prm.accelTorque = torqueValue;
      break;
    case DEC_TORQUE:
      device_prm.decelTorque = torqueValue;
      break;
    case RUN_TORQUE:
      device_prm.runTorque = torqueValue;
      break;
    case HOLD_TORQUE:
      device_prm.holdTorque = torqueValue;
      if (device_prm.motionState != INACTIVE)
      {
        break;
      }
    case CURRENT_TORQUE:
      device_prm.currentTorque = torqueValue;
      STSPIN820_PwmRefSetFreqAndDutyCycle(device_prm.refPwmFreq,torqueValue);
    default:
      device_prm.updateTorque = FALSE;
      break; //ignore error
  }
}

/**********************************************************
 * @brief Enable or disable the torque boost feature
 * @param[in] enable true to enable torque boost, false to disable
 * @retval None
 **********************************************************/
void STSPIN820::STSPIN820_SetTorqueBoostEnable(bool enable)
{
  device_prm.torqueBoostEnable = enable;
}

/**********************************************************
 * @brief Set the torque boost threshold
 * @param[in]  (from 0 to MAX_NUMBER_OF_DEVICES - 1)
 * @param[in] speedThreshold speed threshold above which the step mode is
 * changed to full step
 * @retval None
 **********************************************************/
void STSPIN820::STSPIN820_SetTorqueBoostThreshold(uint16_t speedThreshold)
{
  device_prm.torqueBoostSpeedThreshold = speedThreshold;
}

/**********************************************************
 * @brief  Stops the motor by using the device deceleration
 * @retval true if the command is successfully executed, else false
 * @note The command is not performed if the device is in INACTIVE,
 * STANDBYTOINACTIVE or STANDBY state.
 **********************************************************/
bool STSPIN820::STSPIN820_SoftStop(void)
{
  bool cmdExecuted = FALSE;
  if ((device_prm.motionState & INACTIVE) != INACTIVE)
  {
    device_prm.commandExecuted = (device_command_t) (device_prm.commandExecuted | STSPIN820_SOFT_STOP_BIT_MASK);
    cmdExecuted = TRUE;
  }
  return (cmdExecuted);
}

/**********************************************************
 * @brief Get the frequency of REF PWM of the specified device
 * @retval the frequency of REF PWM in Hz
 * @note
 **********************************************************/
uint32_t STSPIN820::STSPIN820_VrefPwmGetFreq(void)
{
  return device_prm.refPwmFreq;
}

/**********************************************************
 * @brief Set the frequency of REF PWM of the specified device
 * @param[in] newFreq in Hz
 * @retval None
 * @note
 **********************************************************/
void STSPIN820::STSPIN820_VrefPwmSetFreq(uint32_t newFreq)
{
  device_prm.refPwmFreq = newFreq;
  STSPIN820_PwmRefSetFreqAndDutyCycle(newFreq,device_prm.currentTorque);
}

/**********************************************************
 * @brief  Locks until the device state becomes Inactive
 * @retval None
 **********************************************************/
void STSPIN820::STSPIN820_WaitWhileActive(void)
{
  /* Wait while motor is running */
  while (((STSPIN820_GetDeviceState()&INACTIVE)!=INACTIVE)||\
   (((STSPIN820_GetDeviceState()&INACTIVE)==INACTIVE)&&(toggle_odd!=0)));
}

/**********************************************************
 * @brief Updates the current speed of the device
 * @param[in] newSpeed in pps
 * @retval None
 **********************************************************/
void STSPIN820::STSPIN820_ApplySpeed(uint16_t newSpeed)
{
  if (device_prm.torqueBoostEnable != FALSE)
  {
    if (device_prm.stepMode > STEP_MODE_1_256)
    {
      STSPIN820_ErrorHandler(STSPIN820_ERROR_APPLY_SPEED);
    }
    if (device_prm.stepMode != STEP_MODE_FULL)
    {
      if (((newSpeed>>device_prm.stepModeLatched)>\
           device_prm.torqueBoostSpeedThreshold)&&\
          (((device_prm.commandExecuted & STSPIN820_MOVE_BIT_MASK) != MOVE_CMD) ||\
           ((device_prm.stepsToTake-device_prm.relativePos)>=\
            (1<<device_prm.stepModeLatched))))
      {         
        if ((device_prm.sequencerPosition & 0xFF) == 0x80)
       {
          STSPIN820_SetFullStep();
          device_prm.stepMode = (motor_step_mode_t) STEP_MODE_FULL;
          device_prm.accu >>= device_prm.stepModeLatched;
          newSpeed >>= device_prm.stepModeLatched;
       }
      }
    }
    else if (((newSpeed <= device_prm.torqueBoostSpeedThreshold) &&\
              (device_prm.stepModeLatched != STEP_MODE_FULL))||\
             (((device_prm.commandExecuted & STSPIN820_MOVE_BIT_MASK) == MOVE_CMD)&&\
               ((device_prm.stepsToTake-device_prm.relativePos)<=\
                (1<<device_prm.stepModeLatched))))
    {
      STSPIN820_SetStepMode(device_prm.stepModeLatched);
      device_prm.stepMode = device_prm.stepModeLatched;
      device_prm.accu <<= device_prm.stepModeLatched;
      newSpeed <<= device_prm.stepModeLatched;
    }
  }
  else if (device_prm.stepMode != device_prm.stepModeLatched)
  {
    //torqueBoostEnable has just been disabled
    STSPIN820_SetStepMode(device_prm.stepModeLatched);
    device_prm.stepMode = device_prm.stepModeLatched;
    device_prm.accu <<= device_prm.stepModeLatched;
    newSpeed <<= device_prm.stepModeLatched;
  }
  
  if (newSpeed < STSPIN820_MIN_STCK_FREQ)
  {
    newSpeed = STSPIN820_MIN_STCK_FREQ;  
  }
  if (newSpeed > STSPIN820_MAX_STCK_FREQ)
  {
    newSpeed = STSPIN820_MAX_STCK_FREQ;
  }
  
  device_prm.speed = newSpeed;
  STSPIN820_TimStckSetFreq(newSpeed);

}

/**********************************************************
 * @brief Apply the set torque to the specified device
 * @param[in] torqueMode torque mode
 * @retval None
 * @note
 **********************************************************/
void STSPIN820::STSPIN820_ApplyTorque(motor_torque_mode_t torqueMode)
{
  uint8_t torqueValue = 0;
  device_prm.updateTorque = FALSE;
  switch(torqueMode)
  {
    case ACC_TORQUE:
      device_prm.currentTorque = device_prm.accelTorque;
      break;
    case DEC_TORQUE:
      device_prm.currentTorque = device_prm.decelTorque;
      break;
    case RUN_TORQUE:
      device_prm.currentTorque = device_prm.runTorque;
      break;
    case HOLD_TORQUE:
      device_prm.currentTorque = device_prm.holdTorque;
      break;
    case CURRENT_TORQUE:
      break;
    default:
      return; //ignore error
  }
  torqueValue = device_prm.currentTorque;
  STSPIN820_PwmRefSetFreqAndDutyCycle(device_prm.refPwmFreq,torqueValue);
}

/**********************************************************
 * @brief  Computes the speed profile according to the number of steps to move
 * @param[in] nbSteps number of steps to perform
 * @retval None
 * @note Using the acceleration and deceleration of the device,
 * this function determines the duration in steps of the acceleration,
 * steady and deceleration phases.
 * If the total number of steps to perform is big enough, a trapezoidal move
 * is performed (i.e. there is a steady phase where the motor runs at the maximum
 * speed.
 * Else, a triangular move is performed (no steady phase: the maximum speed is never
 * reached.
 **********************************************************/
void STSPIN820::STSPIN820_ComputeSpeedProfile(uint32_t nbSteps)
{
  uint32_t reqAccSteps; 
    uint32_t reqDecSteps;
   
  /* compute the number of steps to get the targeted speed */
  uint16_t minSpeed = device_prm.minSpeed;
  reqAccSteps = (device_prm.maxSpeed - minSpeed);
  reqAccSteps *= (device_prm.maxSpeed + minSpeed);
  reqDecSteps = reqAccSteps;
  reqAccSteps /= (uint32_t)device_prm.acceleration;
  reqAccSteps /= 2;

  /* compute the number of steps to stop */
  reqDecSteps /= (uint32_t)device_prm.deceleration;
  reqDecSteps /= 2;

    if(( reqAccSteps + reqDecSteps ) > nbSteps)
    {   
    /* Triangular move  */
    /* reqDecSteps = (Pos * Dec) /(Dec+Acc) */
    uint32_t dec = device_prm.deceleration;
    uint32_t acc = device_prm.acceleration;
    
    reqDecSteps =  ((uint32_t) dec * nbSteps) / (acc + dec);
    if (reqDecSteps > 1)
    {
      reqAccSteps = reqDecSteps - 1;
      if(reqAccSteps == 0)
      {
        reqAccSteps = 1;
      }      
    }
    else
    {
      reqAccSteps = 0;
    }
    device_prm.endAccPos = reqAccSteps;
    device_prm.startDecPos = reqDecSteps;
    }
    else
    {    
    /* Trapezoidal move */
    /* accelerating phase to endAccPos */
    /* steady phase from  endAccPos to startDecPos */
    /* decelerating from startDecPos to stepsToTake*/
    device_prm.endAccPos = reqAccSteps;
    device_prm.startDecPos = nbSteps - reqDecSteps - 1;
    }
}

/**********************************************************
 * @brief  Handlers of the flag interrupt which calls the user callback (if defined)
 * @retval None
 **********************************************************/
void STSPIN820::STSPIN820_FlagInterruptHandler(void)
{
  if (flag_interrupt_callback != 0)
  {
    flag_interrupt_callback();
  }
}

/**********************************************************
 * @brief  Set the parameters of the device whose values are not defined in
 * STSPIN820_config.h
 * @retval None
 **********************************************************/
void STSPIN820::STSPIN820_SetDeviceParamsOtherValues(void)
{
  uint16_t tmp;

  device_prm.accu = 0;
  device_prm.currentPosition = 0;
  device_prm.sequencerPosition = 0;
  device_prm.endAccPos = 0;
  device_prm.relativePos = 0;
  device_prm.startDecPos = 0;
  device_prm.stepsToTake = 0;
  device_prm.updateTorque = FALSE;
  device_prm.speed = 0;
  device_prm.commandExecuted = NO_CMD;
  device_prm.direction = FORWARD;
  tmp = device_prm.minSpeed;
  if (((device_prm.torqueBoostEnable != FALSE)&&\
       (device_prm.torqueBoostSpeedThreshold>STSPIN820_MAX_STCK_FREQ))||\
      (tmp>device_prm.maxSpeed))
  {
    STSPIN820_ErrorHandler(STSPIN820_ERROR_INIT);
  }
}

/**********************************************************
 * @brief  Set the parameters of the device to values of initDevicePrm structure
 * @param pInitDevicePrm structure containing values to initialize the device 
 * parameters
 * @retval None
 **********************************************************/
void STSPIN820::STSPIN820_SetDeviceParamsToGivenValues(STSPIN820_init_t* pInitDevicePrm)
{
  int i = 100;
  printf("%d\r\n", i++);
  device_prm.motionState = STANDBY;;

  if (STSPIN820_SetAcceleration(pInitDevicePrm->acceleration)==FALSE)
  {
    STSPIN820_ErrorHandler(STSPIN820_ERROR_SET_ACCELERATION);
  }
  printf("%d\r\n", i++);
  if (STSPIN820_SetDeceleration(pInitDevicePrm->deceleration)==FALSE)
  {
    STSPIN820_ErrorHandler(STSPIN820_ERROR_SET_DECELERATION);
  }
  printf("%d\r\n", i++);
  if (STSPIN820_SetMaxSpeed(pInitDevicePrm->maxSpeed)==FALSE)
  {
    STSPIN820_ErrorHandler(STSPIN820_ERROR_SET_MAX_SPEED);
  }
  printf("%d\r\n", i++);
  if (STSPIN820_SetMinSpeed(pInitDevicePrm->minSpeed)==FALSE)
  {
    STSPIN820_ErrorHandler(STSPIN820_ERROR_SET_MIN_SPEED);
  }
  printf("%d\r\n", i++);
  STSPIN820_VrefPwmSetFreq(pInitDevicePrm->vrefPwmFreq);
  STSPIN820_SetTorque(ACC_TORQUE,pInitDevicePrm->accelTorque);
  STSPIN820_SetTorque(DEC_TORQUE,pInitDevicePrm->decelTorque);
  STSPIN820_SetTorque(RUN_TORQUE,pInitDevicePrm->runTorque);
  STSPIN820_SetTorque(HOLD_TORQUE,pInitDevicePrm->holdTorque);
  device_prm.torqueBoostEnable = pInitDevicePrm->torqueBoostEnable;
  device_prm.torqueBoostSpeedThreshold = pInitDevicePrm->torqueBoostSpeedThreshold;
  STSPIN820_SetStopMode(pInitDevicePrm->stopMode);
  printf("%d\r\n", i++);
  STSPIN820_SetDeviceParamsOtherValues();
  printf("%d\r\n", i++);
  /* Eventually deactivate motor */
  if ((device_prm.motionState != INACTIVE)&&\
      (device_prm.motionState != STANDBY))
  {
    STSPIN820_HardHiZ();
  }

  /* Enter standby */
  STSPIN820_Reset();
  
  /* Reset the microstepping sequencer position */
  device_prm.sequencerPosition = 0;

  /* Reset current and mark positions */
  device_prm.currentPosition = 0; 
  device_prm.markPosition = 0;
  
  /* Set predefined step mode */
  STSPIN820_SetStepMode(pInitDevicePrm->stepMode);
  
  /* Wait */
  STSPIN820_Delay(SELECT_STEP_MODE_DELAY);
  
  /* Exit standby */
  STSPIN820_ReleaseReset();
  
    /* Let a delay after reset release*/
  STSPIN820_Delay(AFTER_STANDBY_EXIT_DEAD_TIME);
  
}

/**********************************************************
 * @brief  Sets the parameters of the device to predefined values
 * from STSPIN820_config.h
 * @retval None
 **********************************************************/
void STSPIN820::STSPIN820_SetDeviceParamsToPredefinedValues(void)
{
  device_prm.motionState = STANDBY;

  if (STSPIN820_SetAcceleration(STSPIN820_CONF_PARAM_ACC)==FALSE)
  {
    STSPIN820_ErrorHandler(STSPIN820_ERROR_SET_ACCELERATION);
  }
  if (STSPIN820_SetDeceleration(STSPIN820_CONF_PARAM_DEC)==FALSE)
  {
    STSPIN820_ErrorHandler(STSPIN820_ERROR_SET_DECELERATION);
  }
  if (STSPIN820_SetMaxSpeed(STSPIN820_CONF_PARAM_RUNNING_SPEED)==FALSE)
  {
    STSPIN820_ErrorHandler(STSPIN820_ERROR_SET_MAX_SPEED);
  }
  if (STSPIN820_SetMinSpeed(STSPIN820_CONF_PARAM_MIN_SPEED)==FALSE)
  {
    STSPIN820_ErrorHandler(STSPIN820_ERROR_SET_MIN_SPEED);
  }

  STSPIN820_VrefPwmSetFreq(STSPIN820_CONF_PARAM_REF_PWM_FREQUENCY);
  STSPIN820_SetTorque(ACC_TORQUE,STSPIN820_CONF_PARAM_ACC_TORQUE);
  STSPIN820_SetTorque(DEC_TORQUE,STSPIN820_CONF_PARAM_DEC_TORQUE);
  STSPIN820_SetTorque(RUN_TORQUE,STSPIN820_CONF_PARAM_RUNNING_TORQUE);
  STSPIN820_SetTorque(HOLD_TORQUE,STSPIN820_CONF_PARAM_HOLDING_TORQUE);
  device_prm.torqueBoostEnable = STSPIN820_CONF_PARAM_TORQUE_BOOST_EN;
  device_prm.torqueBoostSpeedThreshold = STSPIN820_CONF_PARAM_TORQUE_BOOST_TH;
  STSPIN820_SetStopMode(STSPIN820_CONF_PARAM_AUTO_HIZ_STOP);

  STSPIN820_SetDeviceParamsOtherValues();
  
    /* Eventually deactivate motor */
  if ((device_prm.motionState != INACTIVE)&&\
      (device_prm.motionState != STANDBY))
  {
    STSPIN820_HardHiZ();
  }

  /* Enter standby */
  STSPIN820_Reset();
  
  /* Reset the microstepping sequencer position */
  device_prm.sequencerPosition = 0;

  /* Reset current and mark positions */
  device_prm.currentPosition = 0; 
  device_prm.markPosition = 0;
  
  /* Set predefined step mode */
  STSPIN820_SetStepMode((motor_step_mode_t) STSPIN820_CONF_PARAM_STEP_MODE);
    
  /* Wait */
  STSPIN820_Delay(SELECT_STEP_MODE_DELAY);
  
  /* Exit standby */
  STSPIN820_ReleaseReset();
  
  /* Let a delay after reset release*/
  STSPIN820_Delay(AFTER_STANDBY_EXIT_DEAD_TIME);
}

/**********************************************************
 * @brief Initialises the bridge parameters to start the movement
 * and enable the power bridge
 * @retval None
 **********************************************************/
void STSPIN820::STSPIN820_StartMovement(void)  
{
  /* Enable STSPIN820 powerstage */
  STSPIN820_Enable();
  toggle_odd = 0;
  device_prm.accu = 0;
  device_prm.relativePos = 0;  
  if ((device_prm.endAccPos == 0)&&\
      (device_prm.commandExecuted != RUN_CMD))
  {
    device_prm.motionState = DECELERATING;
    STSPIN820_ApplyTorque(DEC_TORQUE);
  }
  else
  {
    device_prm.motionState = ACCELERATING;
    STSPIN820_ApplyTorque(ACC_TORQUE);
  }
  STSPIN820_PwmRefStart();
  /* Initialize the step clock timer */
  STSPIN820_TimStckInit();
  /* Program the step clock */
  STSPIN820_TimStckCompareInit();
  STSPIN820_ApplySpeed(device_prm.minSpeed);
  STSPIN820_TimStckStart();
}

/**********************************************************
 * @brief  Handles the device state machine at each pulse
 * @retval None
 * @note Must only be called by the timer ISR
 **********************************************************/
void STSPIN820::STSPIN820_StepClockHandler(void)
{
  uint32_t stepModeShift = device_prm.stepModeLatched - device_prm.stepMode;
  uint16_t tmp;

  if (device_prm.motionState == STANDBYTOINACTIVE)
  {
    if (toggle_odd != 0)
    {
      toggle_odd = 0;
      if (device_prm.sequencerPosition == 0)
      {
        if (STSPIN820_TimStckStop(&toggle_odd) == 0)
        {
          STSPIN820_ErrorHandler(STSPIN820_ERROR_STEP_CLOCK);
        }
        return;
      }      
    }
    else
    {
      toggle_odd = 1;
      tmp = (1 << (STEP_MODE_1_256-device_prm.stepMode));
      device_prm.sequencerPosition -= tmp;
    }
    STSPIN820_TimStckSetFreq(STSPIN820_MAX_STCK_FREQ);
    return;
  }  
  
  if (toggle_odd == 0)
  {
    toggle_odd = 1;
  }
  else
  {
    toggle_odd = 0;
    /* Incrementation of the relative position */
    device_prm.relativePos += (1 << stepModeShift);

    /* Incrementation of the current position */
    if (device_prm.direction != BACKWARD)
    {
      device_prm.currentPosition += (1 << stepModeShift);
      tmp = (1 << (STEP_MODE_1_256-device_prm.stepMode));
      device_prm.sequencerPosition += tmp;
      if (device_prm.sequencerPosition >= (SEQUENCER_MAX_VALUE+1))
      {
        device_prm.sequencerPosition -= (SEQUENCER_MAX_VALUE+1);
      }
    }
    else
    {
      device_prm.currentPosition -= (1 << stepModeShift);
      tmp = (1 << (STEP_MODE_1_256-device_prm.stepMode));
      device_prm.sequencerPosition -= tmp;
      if (device_prm.sequencerPosition < 0)
      {
        device_prm.sequencerPosition += (SEQUENCER_MAX_VALUE+1);
      }
    }

    switch (device_prm.motionState) 
    {
      case ACCELERATING: 
      {
          uint32_t relPos = device_prm.relativePos;
          uint32_t endAccPos = device_prm.endAccPos;
          uint16_t speed = device_prm.speed;
          uint32_t acc = ((uint32_t)device_prm.acceleration << 16)>>stepModeShift;
        
          if (((device_prm.commandExecuted&(STSPIN820_SOFT_STOP_BIT_MASK|STSPIN820_DIR_CHANGE_BIT_MASK))!=0)||\
              ((device_prm.commandExecuted==MOVE_CMD)&&(relPos>=device_prm.startDecPos)))
          {
            device_prm.motionState = DECELERATING;
            device_prm.accu = 0;
            /* Apply decelerating torque */
            STSPIN820_ApplyTorque(DEC_TORQUE);
          }
          else if ((speed>=(device_prm.maxSpeed>>stepModeShift))||\
                   ((device_prm.commandExecuted==MOVE_CMD)&&(relPos >= endAccPos)))
          {
            device_prm.motionState = STEADY;
            /* Apply running torque */
            STSPIN820_ApplyTorque(RUN_TORQUE);
          }
          else
          {
            bool speedUpdated = FALSE;
            /* Go on accelerating */
            if (speed==0)
            {
              speed =1;
            }
            device_prm.accu += acc / speed;
            while (device_prm.accu>=(0X10000L))
            {
              device_prm.accu -= (0X10000L);
              speed +=1;
              speedUpdated = TRUE;
            }
          
            if (speedUpdated)
            {
              if (speed>(device_prm.maxSpeed>>stepModeShift))
              {
                speed = device_prm.maxSpeed>>stepModeShift;
              }    
              device_prm.speed = speed;
            }
            
            if (device_prm.updateTorque!=FALSE)
            {
              /* Apply accelerating torque */
              STSPIN820_ApplyTorque(ACC_TORQUE);              
            }
          }
          break;
      }
      case STEADY: 
      {
        uint16_t maxSpeed = device_prm.maxSpeed>>stepModeShift;
        uint32_t relativePos = device_prm.relativePos;
        if (device_prm.updateTorque!=FALSE)
        {
          /* Apply accelerating torque */
          STSPIN820_ApplyTorque(RUN_TORQUE);
        }
        if  (((device_prm.commandExecuted&(STSPIN820_SOFT_STOP_BIT_MASK|STSPIN820_DIR_CHANGE_BIT_MASK))!=0)||\
             ((device_prm.commandExecuted==MOVE_CMD)&&\
              (relativePos>=(device_prm.startDecPos)))||\
             ((device_prm.commandExecuted==RUN_CMD)&&\
              (device_prm.speed>maxSpeed)))
        {
          device_prm.motionState = DECELERATING;
          device_prm.accu = 0;
          /* Apply decelerating torque */
          STSPIN820_ApplyTorque(DEC_TORQUE);
        }
        else if ((device_prm.commandExecuted==RUN_CMD)&&(device_prm.speed<maxSpeed))
        {
          device_prm.motionState = ACCELERATING;
          device_prm.accu = 0;
          /* Apply accelerating torque */
          STSPIN820_ApplyTorque(ACC_TORQUE);
        }
        break;
      }
      case DECELERATING: 
      {
        uint32_t relativePos = device_prm.relativePos;
        uint16_t speed = device_prm.speed;
        uint32_t dec = ((uint32_t)device_prm.deceleration << 16)>>stepModeShift;
        if ((((device_prm.commandExecuted&(STSPIN820_SOFT_STOP_BIT_MASK|STSPIN820_DIR_CHANGE_BIT_MASK))!=0)&&\
             (speed<=(device_prm.minSpeed>>stepModeShift)))||\
            ((device_prm.commandExecuted==MOVE_CMD)&&(relativePos>=device_prm.stepsToTake)))
        {
          /* Motion process complete */
          if ((device_prm.commandExecuted&STSPIN820_DIR_CHANGE_BIT_MASK)!=0)
          {
            device_prm.commandExecuted = (device_command_t) (device_prm.commandExecuted & ~STSPIN820_DIR_CHANGE_BIT_MASK);
            if (device_prm.direction==BACKWARD)
            {
              device_prm.direction=FORWARD;
            }
            else device_prm.direction=BACKWARD;
            STSPIN820_SetDirectionGpio(device_prm.direction);
            if ((device_prm.commandExecuted&STSPIN820_SOFT_STOP_BIT_MASK)==0)
            {
              device_prm.motionState = ACCELERATING;
              device_prm.accu = 0;
              /* Apply accelerating torque */
              STSPIN820_ApplyTorque(ACC_TORQUE);
              break;
            }
          }
          if (device_prm.stopMode==HOLD_MODE)
          {
            STSPIN820_HardStop();
          }
          else if (device_prm.stopMode==STANDBY_MODE)
          {
            STSPIN820_PutDeviceInStandby();
          }
          else
          {
            STSPIN820_HardHiZ();
          }
        }
        else if ((device_prm.commandExecuted==RUN_CMD)&&
                 (speed<=(device_prm.maxSpeed>>stepModeShift)))
        {
          device_prm.motionState = STEADY;
          /* Apply running torque */
          STSPIN820_ApplyTorque(RUN_TORQUE);
        }
        else
        {
          /* Go on decelerating */
          if (speed>(device_prm.minSpeed>>stepModeShift))
          {
            bool speedUpdated = FALSE;
            if (speed==0)
            {
              speed = 1;
            }
            device_prm.accu += dec / speed;
            while (device_prm.accu>=(0X10000L))
            {
              device_prm.accu -= (0X10000L);
              if (speed>1)
              {  
                speed -=1;
              }
              speedUpdated = TRUE;
            }
          
            if (speedUpdated)
            {
              if (speed<(device_prm.minSpeed>>stepModeShift))
              {
                speed = device_prm.minSpeed>>stepModeShift;
              }  
              device_prm.speed = speed;
            }
            
            if (device_prm.updateTorque!=FALSE)
            {
              /* Apply decelerating torque */
              STSPIN820_ApplyTorque(DEC_TORQUE);
            }
          }
        }
        break;
      }
      default: 
      {
        break;
      }
    }
  }
  if ((device_prm.motionState & INACTIVE) != INACTIVE)
  {
    STSPIN820_ApplySpeed(device_prm.speed);
  }
  else
  {
    if (STSPIN820_TimStckStop(&toggle_odd) == 0)
    {
      STSPIN820_ErrorHandler(STSPIN820_ERROR_STEP_CLOCK);
    }
  }
}

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/