X-CUBE-SPN1-20150128 example source code for one motor compiled under mbed. Tested OK on Nucleo F401. l6474.cpp is modified from original with defines in l6474_target_config.h to select the original behaviour (motor de-energised when halted), or new mode to continue powering with a (reduced) current in the coils (braking/position hold capability). On F401 avoid using mbed's InterruptIn on pins 10-15 (any port). Beware of other conflicts! L0 & F0 are included but untested.
IHM01A1/l6474.cpp
- Committer:
- gregeric
- Date:
- 2015-10-13
- Revision:
- 6:19c1b4a04c24
- Parent:
- 0:b9444a40a999
File content as of revision 6:19c1b4a04c24:
/** ****************************************************************************** * @file l6474.c * @author IPC Rennes * @version V1.5.0 * @date November 12, 2014 * @brief L6474 driver (fully integrated microstepping motor driver) * @note (C) COPYRIGHT 2014 STMicroelectronics ****************************************************************************** * @attention * * <h2><center>© COPYRIGHT(c) 2014 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. * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "l6474.h" /* Private constants ---------------------------------------------------------*/ /** @addtogroup BSP * @{ */ /** @defgroup L6474 * @{ */ /* Private constants ---------------------------------------------------------*/ /** @defgroup L6474_Private_Constants * @{ */ /// Error while initialising the SPI #define L6474_ERROR_0 (0x8000) /// Error: Bad SPI transaction #define L6474_ERROR_1 (0x8001) /// Maximum number of steps #define MAX_STEPS (0x7FFFFFFF) /// Maximum frequency of the PWMs in Hz #define L6474_MAX_PWM_FREQ (10000) /// Minimum frequency of the PWMs in Hz #define L6474_MIN_PWM_FREQ (2) /** * @} */ /* Private variables ---------------------------------------------------------*/ /** @defgroup L6474_Private_Variables * @{ */ /// Function pointer to flag interrupt call back void (*flagInterruptCallback)(void); /// Function pointer to error handler call back void (*errorHandlerCallback)(uint16_t); static volatile uint8_t numberOfDevices; static uint8_t spiTxBursts[L6474_CMD_ARG_MAX_NB_BYTES][MAX_NUMBER_OF_DEVICES]; static uint8_t spiRxBursts[L6474_CMD_ARG_MAX_NB_BYTES][MAX_NUMBER_OF_DEVICES]; static volatile bool spiPreemtionByIsr = FALSE; static volatile bool isrFlag = FALSE; static uint16_t l6474DriverInstance = 0; /// L6474 Device Paramaters structure deviceParams_t devicePrm[MAX_NUMBER_OF_DEVICES]; /** * @} */ /* Private function prototypes -----------------------------------------------*/ /** @defgroup L6474_Private_functions * @{ */ void L6474_ApplySpeed(uint8_t pwmId, uint16_t newSpeed); void L6474_ComputeSpeedProfile(uint8_t deviceId, uint32_t nbSteps); int32_t L6474_ConvertPosition(uint32_t abs_position_reg); void L6474_ErrorHandler(uint16_t error); void L6474_FlagInterruptHandler(void); void L6474_SendCommand(uint8_t deviceId, uint8_t param); void L6474_SetRegisterToPredefinedValues(uint8_t deviceId); void L6474_WriteBytes(uint8_t *pByteToTransmit, uint8_t *pReceivedByte); void L6474_SetDeviceParamsToPredefinedValues(void); void L6474_StartMovement(uint8_t deviceId); void L6474_StepClockHandler(uint8_t deviceId); uint8_t L6474_Tval_Current_to_Par(double Tval); uint8_t L6474_Tmin_Time_to_Par(double Tmin); /** * @} */ /** @defgroup L6474_Exported_Variables * @{ */ /// L6474 motor driver functions pointer structure motorDrv_t l6474Drv = { L6474_Init, L6474_ReadId, L6474_AttachErrorHandler, L6474_AttachFlagInterrupt, 0, L6474_FlagInterruptHandler, L6474_GetAcceleration, L6474_GetCurrentSpeed, L6474_GetDeceleration, L6474_GetDeviceState, L6474_GetFwVersion, L6474_GetMark, L6474_GetMaxSpeed, L6474_GetMinSpeed, L6474_GetPosition, L6474_GoHome, L6474_GoMark, L6474_GoTo, L6474_HardStop, L6474_Move, L6474_ResetAllDevices, L6474_Run, L6474_SetAcceleration, L6474_SetDeceleration, L6474_SetHome, L6474_SetMark, L6474_SetMaxSpeed, L6474_SetMinSpeed, L6474_SoftStop, L6474_StepClockHandler, L6474_WaitWhileActive, L6474_CmdDisable, L6474_CmdEnable, L6474_CmdGetParam, L6474_CmdGetStatus, L6474_CmdNop, L6474_CmdSetParam, L6474_ReadStatusRegister, L6474_ReleaseReset, L6474_Reset, L6474_SelectStepMode, L6474_SetDirection, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L6474_ErrorHandler, 0 }; /** * @} */ /** @defgroup Device_Control_Functions * @{ */ /******************************************************//** * @brief Attaches 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 L6474_AttachErrorHandler(void (*callback)(uint16_t)) { errorHandlerCallback = (void (*)(uint16_t))callback; } /******************************************************//** * @brief Attaches 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 L6474_AttachFlagInterrupt(void (*callback)(void)) { flagInterruptCallback = (void (*)())callback; } /******************************************************//** * @brief Starts the L6474 library * @param[in] nbDevices Number of L6474 devices to use (from 1 to 3) * @retval None **********************************************************/ void L6474_Init(uint8_t nbDevices) { uint32_t i; numberOfDevices = nbDevices; l6474DriverInstance++; /* Initialise the GPIOs */ BSP_MotorControlBoard_GpioInit(nbDevices); if(BSP_MotorControlBoard_SpiInit() != 0) { /* Initialization Error */ L6474_ErrorHandler(L6474_ERROR_0); } /* Initialise the PWMs used for the Step clocks ----------------------------*/ switch (nbDevices) { case 3: BSP_MotorControlBoard_PwmInit(2); case 2: BSP_MotorControlBoard_PwmInit(1); case 1: BSP_MotorControlBoard_PwmInit(0); default: ; } /* Initialise the L6474s ------------------------------------------------*/ /* Standby-reset deactivation */ BSP_MotorControlBoard_ReleaseReset(); /* Let a delay after reset */ BSP_MotorControlBoard_Delay(1); /* Set all registers and context variables to the predefined values from l6474_target_config.h */ L6474_SetDeviceParamsToPredefinedValues(); /* Disable L6474 powerstage */ for (i = 0; i < nbDevices; i++) { L6474_CmdDisable(i); /* Get Status to clear flags after start up */ L6474_CmdGetStatus(i); } } /******************************************************//** * @brief Returns the acceleration of the specified device * @param[in] deviceId (from 0 to 2) * @retval Acceleration in pps^2 **********************************************************/ uint16_t L6474_GetAcceleration(uint8_t deviceId) { return (devicePrm[deviceId].acceleration); } /******************************************************//** * @brief Returns the current speed of the specified device * @param[in] deviceId (from 0 to 2) * @retval Speed in pps **********************************************************/ uint16_t L6474_GetCurrentSpeed(uint8_t deviceId) { return devicePrm[deviceId].speed; } /******************************************************//** * @brief Returns the deceleration of the specified device * @param[in] deviceId (from 0 to 2) * @retval Deceleration in pps^2 **********************************************************/ uint16_t L6474_GetDeceleration(uint8_t deviceId) { return (devicePrm[deviceId].deceleration); } /******************************************************//** * @brief Returns the device state * @param[in] deviceId (from 0 to 2) * @retval State (ACCELERATING, DECELERATING, STEADY or INACTIVE) **********************************************************/ motorState_t L6474_GetDeviceState(uint8_t deviceId) { return devicePrm[deviceId].motionState; } /******************************************************//** * @brief Returns the FW version of the library * @param None * @retval L6474_FW_VERSION **********************************************************/ uint8_t L6474_GetFwVersion(void) { return (L6474_FW_VERSION); } /******************************************************//** * @brief Return motor handle (pointer to the L6474 motor driver structure) * @param None * @retval Pointer to the motorDrv_t structure **********************************************************/ motorDrv_t* L6474_GetMotorHandle(void) { return (&l6474Drv); } /******************************************************//** * @brief Returns the mark position of the specified device * @param[in] deviceId (from 0 to 2) * @retval Mark register value converted in a 32b signed integer **********************************************************/ int32_t L6474_GetMark(uint8_t deviceId) { return L6474_ConvertPosition(L6474_CmdGetParam(deviceId,L6474_MARK)); } /******************************************************//** * @brief Returns the max speed of the specified device * @param[in] deviceId (from 0 to 2) * @retval maxSpeed in pps **********************************************************/ uint16_t L6474_GetMaxSpeed(uint8_t deviceId) { return (devicePrm[deviceId].maxSpeed); } /******************************************************//** * @brief Returns the min speed of the specified device * @param[in] deviceId (from 0 to 2) * @retval minSpeed in pps **********************************************************/ uint16_t L6474_GetMinSpeed(uint8_t deviceId) { return (devicePrm[deviceId].minSpeed); } /******************************************************//** * @brief Returns the ABS_POSITION of the specified device * @param[in] deviceId (from 0 to 2) * @retval ABS_POSITION register value converted in a 32b signed integer **********************************************************/ int32_t L6474_GetPosition(uint8_t deviceId) { return L6474_ConvertPosition(L6474_CmdGetParam(deviceId,L6474_ABS_POS)); } /******************************************************//** * @brief Requests the motor to move to the home position (ABS_POSITION = 0) * @param[in] deviceId (from 0 to 2) * @retval None **********************************************************/ void L6474_GoHome(uint8_t deviceId) { L6474_GoTo(deviceId, 0); } /******************************************************//** * @brief Requests the motor to move to the mark position * @param[in] deviceId (from 0 to 2) * @retval None **********************************************************/ void L6474_GoMark(uint8_t deviceId) { uint32_t mark; mark = L6474_ConvertPosition(L6474_CmdGetParam(deviceId,L6474_MARK)); L6474_GoTo(deviceId,mark); } /******************************************************//** * @brief Requests the motor to move to the specified position * @param[in] deviceId (from 0 to 2) * @param[in] targetPosition absolute position in steps * @retval None **********************************************************/ void L6474_GoTo(uint8_t deviceId, int32_t targetPosition) { motorDir_t direction; int32_t steps; /* Eventually deactivate motor */ if (devicePrm[deviceId].motionState != INACTIVE) { L6474_HardStop(deviceId); } /* Get current position */ devicePrm[deviceId].currentPosition = L6474_ConvertPosition(L6474_CmdGetParam(deviceId,L6474_ABS_POS)); /* Compute the number of steps to perform */ steps = targetPosition - devicePrm[deviceId].currentPosition; if (steps >= 0) { devicePrm[deviceId].stepsToTake = steps; direction = FORWARD; } else { devicePrm[deviceId].stepsToTake = -steps; direction = BACKWARD; } if (steps != 0) { devicePrm[deviceId].commandExecuted = MOVE_CMD; /* Direction setup */ L6474_SetDirection(deviceId,direction); L6474_ComputeSpeedProfile(deviceId, devicePrm[deviceId].stepsToTake); /* Motor activation */ L6474_StartMovement(deviceId); } } /******************************************************//** * @brief Immediatly stops the motor and disable the power bridge * @param[in] deviceId (from 0 to 2) * @retval None **********************************************************/ void L6474_HardStop(uint8_t deviceId) { /* Disable corresponding PWM */ BSP_MotorControlBoard_PwmStop(deviceId); /* Disable power stage */ #ifndef L6474_CONF_BRAKE_WHEN_HALTED L6474_CmdDisable(deviceId); #else /* Set powerstage to reduced current, retaining position */ switch (deviceId) { case 0: L6474_CmdSetParam(deviceId, L6474_TVAL, L6474_Tval_Current_to_Par(L6474_CONF_PARAM_TVAL_DEVICE_0/L6474_CONF_BRAKE_CURRENT_FACTOR)); break; case 1: L6474_CmdSetParam(deviceId, L6474_TVAL, L6474_Tval_Current_to_Par(L6474_CONF_PARAM_TVAL_DEVICE_1/L6474_CONF_BRAKE_CURRENT_FACTOR)); break; case 2: L6474_CmdSetParam(deviceId, L6474_TVAL, L6474_Tval_Current_to_Par(L6474_CONF_PARAM_TVAL_DEVICE_2/L6474_CONF_BRAKE_CURRENT_FACTOR)); break; default: ; } #endif /* Set inactive state */ devicePrm[deviceId].motionState = INACTIVE; devicePrm[deviceId].commandExecuted = NO_CMD; devicePrm[deviceId].stepsToTake = MAX_STEPS; } /******************************************************//** * @brief Moves the motor of the specified number of steps * @param[in] deviceId (from 0 to 2) * @param[in] direction FORWARD or BACKWARD * @param[in] stepCount Number of steps to perform * @retval None **********************************************************/ void L6474_Move(uint8_t deviceId, motorDir_t direction, uint32_t stepCount) { /* Eventually deactivate motor */ if (devicePrm[deviceId].motionState != INACTIVE) { L6474_HardStop(deviceId); } if (stepCount != 0) { devicePrm[deviceId].stepsToTake = stepCount; devicePrm[deviceId].commandExecuted = MOVE_CMD; devicePrm[deviceId].currentPosition = L6474_ConvertPosition(L6474_CmdGetParam(deviceId,L6474_ABS_POS)); /* Direction setup */ L6474_SetDirection(deviceId,direction); L6474_ComputeSpeedProfile(deviceId, stepCount); /* Motor activation */ L6474_StartMovement(deviceId); } } /******************************************************//** * @brief Read id * @param None * @retval Id of the l6474 Driver Instance **********************************************************/ uint16_t L6474_ReadId(void) { return(l6474DriverInstance); } /******************************************************//** * @brief Resets all L6474 devices * @param None * @retval None **********************************************************/ void L6474_ResetAllDevices(void) { uint8_t loop; for (loop = 0; loop < numberOfDevices; loop++) { /* Stop movement and disable power stage*/ L6474_HardStop(loop); #ifdef L6474_CONF_BRAKE_WHEN_HALTED /* Disable corresponding PWM */ BSP_MotorControlBoard_PwmStop(loop); /* Disable power stage */ L6474_CmdDisable(loop); #endif } L6474_Reset(); BSP_MotorControlBoard_Delay(1); // Reset pin must be forced low for at least 10us BSP_MotorControlBoard_ReleaseReset(); BSP_MotorControlBoard_Delay(1); } /******************************************************//** * @brief Runs the motor. It will accelerate from the min * speed up to the max speed by using the device acceleration. * @param[in] deviceId (from 0 to 2) * @param[in] direction FORWARD or BACKWARD * @retval None **********************************************************/ void L6474_Run(uint8_t deviceId, motorDir_t direction) { /* Eventually deactivate motor */ if (devicePrm[deviceId].motionState != INACTIVE) { L6474_HardStop(deviceId); } /* Direction setup */ L6474_SetDirection(deviceId,direction); devicePrm[deviceId].commandExecuted = RUN_CMD; /* Motor activation */ L6474_StartMovement(deviceId); } /******************************************************//** * @brief Changes the acceleration of the specified device * @param[in] deviceId (from 0 to 2) * @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 is the device is executing * a MOVE or GOTO command (but it can be used during a RUN command) **********************************************************/ bool L6474_SetAcceleration(uint8_t deviceId,uint16_t newAcc) { bool cmdExecuted = FALSE; if ((newAcc != 0)&& ((devicePrm[deviceId].motionState == INACTIVE)|| (devicePrm[deviceId].commandExecuted == RUN_CMD))) { devicePrm[deviceId].acceleration = newAcc; cmdExecuted = TRUE; } return cmdExecuted; } /******************************************************//** * @brief Changes the deceleration of the specified device * @param[in] deviceId (from 0 to 2) * @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 is the device is executing * a MOVE or GOTO command (but it can be used during a RUN command) **********************************************************/ bool L6474_SetDeceleration(uint8_t deviceId, uint16_t newDec) { bool cmdExecuted = FALSE; if ((newDec != 0)&& ((devicePrm[deviceId].motionState == INACTIVE)|| (devicePrm[deviceId].commandExecuted == RUN_CMD))) { devicePrm[deviceId].deceleration = newDec; cmdExecuted = TRUE; } return cmdExecuted; } /******************************************************//** * @brief Set current position to be the Home position (ABS pos set to 0) * @param[in] deviceId (from 0 to 2) * @retval None **********************************************************/ void L6474_SetHome(uint8_t deviceId) { L6474_CmdSetParam(deviceId, L6474_ABS_POS, 0); } /******************************************************//** * @brief Sets current position to be the Mark position * @param[in] deviceId (from 0 to 2) * @retval None **********************************************************/ void L6474_SetMark(uint8_t deviceId) { uint32_t mark = L6474_CmdGetParam(deviceId,L6474_ABS_POS); L6474_CmdSetParam(deviceId,L6474_MARK, mark); } /******************************************************//** * @brief Changes the max speed of the specified device * @param[in] deviceId (from 0 to 2) * @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 L6474_SetMaxSpeed(uint8_t deviceId, uint16_t newMaxSpeed) { bool cmdExecuted = FALSE; if ((newMaxSpeed >= L6474_MIN_PWM_FREQ)&& (newMaxSpeed <= L6474_MAX_PWM_FREQ) && (devicePrm[deviceId].minSpeed <= newMaxSpeed) && ((devicePrm[deviceId].motionState == INACTIVE)|| (devicePrm[deviceId].commandExecuted == RUN_CMD))) { devicePrm[deviceId].maxSpeed = newMaxSpeed; cmdExecuted = TRUE; } return cmdExecuted; } /******************************************************//** * @brief Changes the min speed of the specified device * @param[in] deviceId (from 0 to 2) * @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 L6474_SetMinSpeed(uint8_t deviceId, uint16_t newMinSpeed) { bool cmdExecuted = FALSE; if ((newMinSpeed >= L6474_MIN_PWM_FREQ)&& (newMinSpeed <= L6474_MAX_PWM_FREQ) && (newMinSpeed <= devicePrm[deviceId].maxSpeed) && ((devicePrm[deviceId].motionState == INACTIVE)|| (devicePrm[deviceId].commandExecuted == RUN_CMD))) { devicePrm[deviceId].minSpeed = newMinSpeed; cmdExecuted = TRUE; } return cmdExecuted; } /******************************************************//** * @brief Stops the motor by using the device deceleration * @param[in] deviceId (from 0 to 2) * @retval true if the command is successfully executed, else false * @note The command is not performed is the device is in INACTIVE state. **********************************************************/ bool L6474_SoftStop(uint8_t deviceId) { bool cmdExecuted = FALSE; if (devicePrm[deviceId].motionState != INACTIVE) { devicePrm[deviceId].commandExecuted = SOFT_STOP_CMD; cmdExecuted = TRUE; } return (cmdExecuted); } /******************************************************//** * @brief Locks until the device state becomes Inactive * @param[in] deviceId (from 0 to 2) * @retval None **********************************************************/ void L6474_WaitWhileActive(uint8_t deviceId) { /* Wait while motor is running */ while (L6474_GetDeviceState(deviceId) != INACTIVE); } /** * @} */ /** @defgroup L6474_Control_Functions * @{ */ /******************************************************//** * @brief Issue the Disable command to the L6474 of the specified device * @param[in] deviceId (from 0 to 2) * @retval None **********************************************************/ void L6474_CmdDisable(uint8_t deviceId) { L6474_SendCommand(deviceId, L6474_DISABLE); } /******************************************************//** * @brief Issues the Enable command to the L6474 of the specified device * @param[in] deviceId (from 0 to 2) * @retval None **********************************************************/ void L6474_CmdEnable(uint8_t deviceId) { L6474_SendCommand(deviceId, L6474_ENABLE); } /******************************************************//** * @brief Issues the GetParam command to the L6474 of the specified device * @param[in] deviceId (from 0 to 2) * @param[in] param Register adress (L6474_ABS_POS, L6474_MARK,...) * @retval Register value **********************************************************/ uint32_t L6474_CmdGetParam(uint8_t deviceId, uint32_t param) { uint32_t i; uint32_t spiRxData; uint8_t maxArgumentNbBytes = 0; uint8_t spiIndex = numberOfDevices - deviceId - 1; bool itDisable = FALSE; do { spiPreemtionByIsr = FALSE; if (itDisable) { /* re-enable BSP_MotorControlBoard_EnableIrq if disable in previous iteration */ BSP_MotorControlBoard_EnableIrq(); itDisable = FALSE; } for (i = 0; i < numberOfDevices; i++) { spiTxBursts[0][i] = L6474_NOP; spiTxBursts[1][i] = L6474_NOP; spiTxBursts[2][i] = L6474_NOP; spiTxBursts[3][i] = L6474_NOP; spiRxBursts[1][i] = 0; spiRxBursts[2][i] = 0; spiRxBursts[3][i] = 0; } switch (param) { case L6474_ABS_POS: ; case L6474_MARK: spiTxBursts[0][spiIndex] = ((uint8_t)L6474_GET_PARAM )| (param); maxArgumentNbBytes = 3; break; case L6474_EL_POS: ; case L6474_CONFIG: ; case L6474_STATUS: spiTxBursts[1][spiIndex] = ((uint8_t)L6474_GET_PARAM )| (param); maxArgumentNbBytes = 2; break; default: spiTxBursts[2][spiIndex] = ((uint8_t)L6474_GET_PARAM )| (param); maxArgumentNbBytes = 1; } /* Disable interruption before checking */ /* pre-emption by ISR and SPI transfers*/ BSP_MotorControlBoard_DisableIrq(); itDisable = TRUE; } while (spiPreemtionByIsr); // check pre-emption by ISR for (i = L6474_CMD_ARG_MAX_NB_BYTES-1-maxArgumentNbBytes; i < L6474_CMD_ARG_MAX_NB_BYTES; i++) { L6474_WriteBytes(&spiTxBursts[i][0], &spiRxBursts[i][0]); } spiRxData = ((uint32_t)spiRxBursts[1][spiIndex] << 16)| (spiRxBursts[2][spiIndex] << 8) | (spiRxBursts[3][spiIndex]); /* re-enable BSP_MotorControlBoard_EnableIrq after SPI transfers*/ BSP_MotorControlBoard_EnableIrq(); return (spiRxData); } /******************************************************//** * @brief Issues the GetStatus command to the L6474 of the specified device * @param[in] deviceId (from 0 to 2) * @retval Status Register value * @note Once the GetStatus command is performed, the flags of the status register * are reset. This is not the case when the status register is read with the * GetParam command (via the functions L6474ReadStatusRegister or L6474CmdGetParam). **********************************************************/ uint16_t L6474_CmdGetStatus(uint8_t deviceId) { uint32_t i; uint16_t status; uint8_t spiIndex = numberOfDevices - deviceId - 1; bool itDisable = FALSE; do { spiPreemtionByIsr = FALSE; if (itDisable) { /* re-enable BSP_MotorControlBoard_EnableIrq if disable in previous iteration */ BSP_MotorControlBoard_EnableIrq(); itDisable = FALSE; } for (i = 0; i < numberOfDevices; i++) { spiTxBursts[0][i] = L6474_NOP; spiTxBursts[1][i] = L6474_NOP; spiTxBursts[2][i] = L6474_NOP; spiRxBursts[1][i] = 0; spiRxBursts[2][i] = 0; } spiTxBursts[0][spiIndex] = L6474_GET_STATUS; /* Disable interruption before checking */ /* pre-emption by ISR and SPI transfers*/ BSP_MotorControlBoard_DisableIrq(); itDisable = TRUE; } while (spiPreemtionByIsr); // check pre-emption by ISR for (i = 0; i < L6474_CMD_ARG_NB_BYTES_GET_STATUS + L6474_RSP_NB_BYTES_GET_STATUS; i++) { L6474_WriteBytes(&spiTxBursts[i][0], &spiRxBursts[i][0]); } status = (spiRxBursts[1][spiIndex] << 8) | (spiRxBursts[2][spiIndex]); /* re-enable BSP_MotorControlBoard_EnableIrq after SPI transfers*/ BSP_MotorControlBoard_EnableIrq(); return (status); } /******************************************************//** * @brief Issues the Nop command to the L6474 of the specified device * @param[in] deviceId (from 0 to 2) * @retval None **********************************************************/ void L6474_CmdNop(uint8_t deviceId) { L6474_SendCommand(deviceId, L6474_NOP); } /******************************************************//** * @brief Issues the SetParam command to the L6474 of the specified device * @param[in] deviceId (from 0 to 2) * @param[in] param Register adress (L6474_ABS_POS, L6474_MARK,...) * @param[in] value Value to set in the register * @retval None **********************************************************/ void L6474_CmdSetParam(uint8_t deviceId, uint32_t param, uint32_t value) { uint32_t i; uint8_t maxArgumentNbBytes = 0; uint8_t spiIndex = numberOfDevices - deviceId - 1; bool itDisable = FALSE; do { spiPreemtionByIsr = FALSE; if (itDisable) { /* re-enable BSP_MotorControlBoard_EnableIrq if disable in previous iteration */ BSP_MotorControlBoard_EnableIrq(); itDisable = FALSE; } for (i = 0; i < numberOfDevices; i++) { spiTxBursts[0][i] = L6474_NOP; spiTxBursts[1][i] = L6474_NOP; spiTxBursts[2][i] = L6474_NOP; spiTxBursts[3][i] = L6474_NOP; } switch (param) { case L6474_ABS_POS: ; case L6474_MARK: spiTxBursts[0][spiIndex] = param; spiTxBursts[1][spiIndex] = (uint8_t)(value >> 16); spiTxBursts[2][spiIndex] = (uint8_t)(value >> 8); maxArgumentNbBytes = 3; break; case L6474_EL_POS: ; case L6474_CONFIG: spiTxBursts[1][spiIndex] = param; spiTxBursts[2][spiIndex] = (uint8_t)(value >> 8); maxArgumentNbBytes = 2; break; default: spiTxBursts[2][spiIndex] = param; maxArgumentNbBytes = 1; } spiTxBursts[3][spiIndex] = (uint8_t)(value); /* Disable interruption before checking */ /* pre-emption by ISR and SPI transfers*/ BSP_MotorControlBoard_DisableIrq(); itDisable = TRUE; } while (spiPreemtionByIsr); // check pre-emption by ISR /* SPI transfer */ for (i = L6474_CMD_ARG_MAX_NB_BYTES-1-maxArgumentNbBytes; i < L6474_CMD_ARG_MAX_NB_BYTES; i++) { L6474_WriteBytes(&spiTxBursts[i][0],&spiRxBursts[i][0]); } /* re-enable BSP_MotorControlBoard_EnableIrq after SPI transfers*/ BSP_MotorControlBoard_EnableIrq(); } /******************************************************//** * @brief Reads the Status Register value * @param[in] deviceId (from 0 to 2) * @retval Status register valued * @note The status register flags are not cleared * at the difference with L6474CmdGetStatus() **********************************************************/ uint16_t L6474_ReadStatusRegister(uint8_t deviceId) { return (L6474_CmdGetParam(deviceId,L6474_STATUS)); } /******************************************************//** * @brief Releases the L6474 reset (pin set to High) of all devices * @param None * @retval None **********************************************************/ void L6474_ReleaseReset(void) { BSP_MotorControlBoard_ReleaseReset(); } /******************************************************//** * @brief Resets the L6474 (reset pin set to low) of all devices * @param None * @retval None **********************************************************/ void L6474_Reset(void) { BSP_MotorControlBoard_Reset(); } /******************************************************//** * @brief Set the stepping mode * @param[in] deviceId (from 0 to 2) * @param[in] stepMod from full step to 1/16 microstep as specified in enum motorStepMode_t * @retval None **********************************************************/ void L6474_SelectStepMode(uint8_t deviceId, motorStepMode_t stepMod) { uint8_t stepModeRegister; L6474_STEP_SEL_t l6474StepMod; switch (stepMod) { case STEP_MODE_FULL: l6474StepMod = L6474_STEP_SEL_1; break; case STEP_MODE_HALF: l6474StepMod = L6474_STEP_SEL_1_2; break; case STEP_MODE_1_4: l6474StepMod = L6474_STEP_SEL_1_4; break; case STEP_MODE_1_8: l6474StepMod = L6474_STEP_SEL_1_8; break; case STEP_MODE_1_16: default: l6474StepMod = L6474_STEP_SEL_1_16; break; } /* Eventually deactivate motor */ if (devicePrm[deviceId].motionState != INACTIVE) { L6474_HardStop(deviceId); } /* Read Step mode register and clear STEP_SEL field */ stepModeRegister = (uint8_t)(0xF8 & L6474_CmdGetParam(deviceId,L6474_STEP_MODE)) ; /* Apply new step mode */ L6474_CmdSetParam(deviceId, L6474_STEP_MODE, stepModeRegister | (uint8_t)l6474StepMod); /* Reset abs pos register */ L6474_SetHome(deviceId); } /******************************************************//** * @brief Specifies the direction * @param[in] deviceId (from 0 to 2) * @param[in] dir FORWARD or BACKWARD * @note The direction change is only applied if the device * is in INACTIVE state * @retval None **********************************************************/ void L6474_SetDirection(uint8_t deviceId, motorDir_t dir) { if (devicePrm[deviceId].motionState == INACTIVE) { devicePrm[deviceId].direction = dir; BSP_MotorControlBoard_SetDirectionGpio(deviceId, dir); } } /** * @} */ /** @addtogroup L6474_Private_functions * @{ */ /******************************************************//** * @brief Updates the current speed of the device * @param[in] deviceId (from 0 to 2) * @param[in] newSpeed in pps * @retval None **********************************************************/ void L6474_ApplySpeed(uint8_t deviceId, uint16_t newSpeed) { if (newSpeed < L6474_MIN_PWM_FREQ) { newSpeed = L6474_MIN_PWM_FREQ; } if (newSpeed > L6474_MAX_PWM_FREQ) { newSpeed = L6474_MAX_PWM_FREQ; } devicePrm[deviceId].speed = newSpeed; switch (deviceId) { case 0: BSP_MotorControlBoard_Pwm1SetFreq(newSpeed); break; case 1: BSP_MotorControlBoard_Pwm2SetFreq(newSpeed); break; case 2: BSP_MotorControlBoard_Pwm3SetFreq(newSpeed); break; default: break; //ignore error } } /******************************************************//** * @brief Computes the speed profile according to the number of steps to move * @param[in] deviceId (from 0 to 2) * @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 L6474_ComputeSpeedProfile(uint8_t deviceId, uint32_t nbSteps) { uint32_t reqAccSteps; uint32_t reqDecSteps; /* compute the number of steps to get the targeted speed */ uint16_t minSpeed = devicePrm[deviceId].minSpeed; reqAccSteps = (devicePrm[deviceId].maxSpeed - minSpeed); reqAccSteps *= (devicePrm[deviceId].maxSpeed + minSpeed); reqDecSteps = reqAccSteps; reqAccSteps /= (uint32_t)devicePrm[deviceId].acceleration; reqAccSteps /= 2; /* compute the number of steps to stop */ reqDecSteps /= (uint32_t)devicePrm[deviceId].deceleration; reqDecSteps /= 2; if(( reqAccSteps + reqDecSteps ) > nbSteps) { /* Triangular move */ /* reqDecSteps = (Pos * Dec) /(Dec+Acc) */ uint32_t dec = devicePrm[deviceId].deceleration; uint32_t acc = devicePrm[deviceId].acceleration; reqDecSteps = ((uint32_t) dec * nbSteps) / (acc + dec); if (reqDecSteps > 1) { reqAccSteps = reqDecSteps - 1; if(reqAccSteps == 0) { reqAccSteps = 1; } } else { reqAccSteps = 0; } devicePrm[deviceId].endAccPos = reqAccSteps; devicePrm[deviceId].startDecPos = reqDecSteps; } else { /* Trapezoidal move */ /* accelerating phase to endAccPos */ /* steady phase from endAccPos to startDecPos */ /* decelerating from startDecPos to stepsToTake*/ devicePrm[deviceId].endAccPos = reqAccSteps; devicePrm[deviceId].startDecPos = nbSteps - reqDecSteps - 1; } } /******************************************************//** * @brief Converts the ABS_POSITION register value to a 32b signed integer * @param[in] abs_position_reg value of the ABS_POSITION register * @retval operation_result 32b signed integer corresponding to the absolute position **********************************************************/ int32_t L6474_ConvertPosition(uint32_t abs_position_reg) { int32_t operation_result; if (abs_position_reg & L6474_ABS_POS_SIGN_BIT_MASK) { /* Negative register value */ abs_position_reg = ~abs_position_reg; abs_position_reg += 1; operation_result = (int32_t) (abs_position_reg & L6474_ABS_POS_VALUE_MASK); operation_result = -operation_result; } else { operation_result = (int32_t) abs_position_reg; } return operation_result; } /******************************************************//** * @brief Error handler which calls the user callback (if defined) * @param[in] error Number of the error * @retval None **********************************************************/ void L6474_ErrorHandler(uint16_t error) { if (errorHandlerCallback != 0) { (void) errorHandlerCallback(error); } else { while(1) { /* Infinite loop */ } } } /******************************************************//** * @brief Handlers of the flag interrupt which calls the user callback (if defined) * @param None * @retval None **********************************************************/ void L6474_FlagInterruptHandler(void) { if (flagInterruptCallback != 0) { /* Set isr flag */ isrFlag = TRUE; flagInterruptCallback(); /* Reset isr flag */ isrFlag = FALSE; } } /******************************************************//** * @brief Sends a command without arguments to the L6474 via the SPI * @param[in] deviceId (from 0 to 2) * @param[in] param Command to send * @retval None **********************************************************/ void L6474_SendCommand(uint8_t deviceId, uint8_t param) { uint32_t i; uint8_t spiIndex = numberOfDevices - deviceId - 1; bool itDisable = FALSE; do { spiPreemtionByIsr = FALSE; if (itDisable) { /* re-enable BSP_MotorControlBoard_EnableIrq if disable in previous iteration */ BSP_MotorControlBoard_EnableIrq(); itDisable = FALSE; } for (i = 0; i < numberOfDevices; i++) { spiTxBursts[3][i] = L6474_NOP; } spiTxBursts[3][spiIndex] = param; /* Disable interruption before checking */ /* pre-emption by ISR and SPI transfers*/ BSP_MotorControlBoard_DisableIrq(); itDisable = TRUE; } while (spiPreemtionByIsr); // check pre-emption by ISR L6474_WriteBytes(&spiTxBursts[3][0], &spiRxBursts[3][0]); /* re-enable BSP_MotorControlBoard_EnableIrq after SPI transfers*/ BSP_MotorControlBoard_EnableIrq(); } /******************************************************//** * @brief Sets the registers of the L6474 to their predefined values * from l6474_target_config.h * @param[in] deviceId (from 0 to 2) * @retval None **********************************************************/ void L6474_SetRegisterToPredefinedValues(uint8_t deviceId) { L6474_CmdSetParam(deviceId, L6474_ABS_POS, 0); L6474_CmdSetParam(deviceId, L6474_EL_POS, 0); L6474_CmdSetParam(deviceId, L6474_MARK, 0); switch (deviceId) { case 0: L6474_CmdSetParam(deviceId, L6474_TVAL, L6474_Tval_Current_to_Par(L6474_CONF_PARAM_TVAL_DEVICE_0)); L6474_CmdSetParam(deviceId, L6474_T_FAST, (uint8_t)L6474_CONF_PARAM_TOFF_FAST_DEVICE_0 | (uint8_t)L6474_CONF_PARAM_FAST_STEP_DEVICE_0); L6474_CmdSetParam(deviceId, L6474_TON_MIN, L6474_Tmin_Time_to_Par(L6474_CONF_PARAM_TON_MIN_DEVICE_0) ); L6474_CmdSetParam(deviceId, L6474_TOFF_MIN, L6474_Tmin_Time_to_Par(L6474_CONF_PARAM_TOFF_MIN_DEVICE_0)); L6474_CmdSetParam(deviceId, L6474_OCD_TH, L6474_CONF_PARAM_OCD_TH_DEVICE_0); L6474_CmdSetParam(deviceId, L6474_STEP_MODE, (uint8_t)L6474_CONF_PARAM_STEP_SEL_DEVICE_0 | (uint8_t)L6474_CONF_PARAM_SYNC_SEL_DEVICE_0); L6474_CmdSetParam(deviceId, L6474_ALARM_EN, L6474_CONF_PARAM_ALARM_EN_DEVICE_0); L6474_CmdSetParam(deviceId, L6474_CONFIG, (uint16_t)L6474_CONF_PARAM_CLOCK_SETTING_DEVICE_0 | (uint16_t)L6474_CONF_PARAM_TQ_REG_DEVICE_0 | (uint16_t)L6474_CONF_PARAM_OC_SD_DEVICE_0 | (uint16_t)L6474_CONF_PARAM_SR_DEVICE_0 | (uint16_t)L6474_CONF_PARAM_TOFF_DEVICE_0); break; case 1: L6474_CmdSetParam(deviceId, L6474_TVAL, L6474_Tval_Current_to_Par(L6474_CONF_PARAM_TVAL_DEVICE_1)); L6474_CmdSetParam(deviceId, L6474_T_FAST, (uint8_t)L6474_CONF_PARAM_TOFF_FAST_DEVICE_1 | (uint8_t)L6474_CONF_PARAM_FAST_STEP_DEVICE_1); L6474_CmdSetParam(deviceId, L6474_TON_MIN, L6474_Tmin_Time_to_Par(L6474_CONF_PARAM_TON_MIN_DEVICE_1)); L6474_CmdSetParam(deviceId, L6474_TOFF_MIN, L6474_Tmin_Time_to_Par(L6474_CONF_PARAM_TOFF_MIN_DEVICE_1)); L6474_CmdSetParam(deviceId, L6474_OCD_TH, L6474_CONF_PARAM_OCD_TH_DEVICE_1); L6474_CmdSetParam(deviceId, L6474_STEP_MODE, (uint8_t)L6474_CONF_PARAM_STEP_SEL_DEVICE_1 | (uint8_t)L6474_CONF_PARAM_SYNC_SEL_DEVICE_1); L6474_CmdSetParam(deviceId, L6474_ALARM_EN, L6474_CONF_PARAM_ALARM_EN_DEVICE_1); L6474_CmdSetParam(deviceId, L6474_CONFIG, (uint16_t)L6474_CONF_PARAM_CLOCK_SETTING_DEVICE_1 | (uint16_t)L6474_CONF_PARAM_TQ_REG_DEVICE_1 | (uint16_t)L6474_CONF_PARAM_OC_SD_DEVICE_1 | (uint16_t)L6474_CONF_PARAM_SR_DEVICE_1 | (uint16_t)L6474_CONF_PARAM_TOFF_DEVICE_1); break; case 2: L6474_CmdSetParam(deviceId, L6474_TVAL, L6474_Tval_Current_to_Par(L6474_CONF_PARAM_TVAL_DEVICE_2)); L6474_CmdSetParam(deviceId, L6474_T_FAST, (uint8_t)L6474_CONF_PARAM_TOFF_FAST_DEVICE_2 | (uint8_t)L6474_CONF_PARAM_FAST_STEP_DEVICE_2); L6474_CmdSetParam(deviceId, L6474_TON_MIN, L6474_Tmin_Time_to_Par(L6474_CONF_PARAM_TON_MIN_DEVICE_2)); L6474_CmdSetParam(deviceId, L6474_TOFF_MIN, L6474_Tmin_Time_to_Par(L6474_CONF_PARAM_TOFF_MIN_DEVICE_2)); L6474_CmdSetParam(deviceId, L6474_OCD_TH, L6474_CONF_PARAM_OCD_TH_DEVICE_2); L6474_CmdSetParam(deviceId, L6474_STEP_MODE, (uint8_t)L6474_CONF_PARAM_STEP_SEL_DEVICE_2 | (uint8_t)L6474_CONF_PARAM_SYNC_SEL_DEVICE_2); L6474_CmdSetParam(deviceId, L6474_ALARM_EN, L6474_CONF_PARAM_ALARM_EN_DEVICE_2); L6474_CmdSetParam(deviceId, L6474_CONFIG, (uint16_t)L6474_CONF_PARAM_CLOCK_SETTING_DEVICE_2 | (uint16_t)L6474_CONF_PARAM_TQ_REG_DEVICE_2 | (uint16_t)L6474_CONF_PARAM_OC_SD_DEVICE_2 | (uint16_t)L6474_CONF_PARAM_SR_DEVICE_2 | (uint16_t)L6474_CONF_PARAM_TOFF_DEVICE_2); break; default: ; } } /******************************************************//** * @brief Sets the parameters of the device to predefined values * from l6474_target_config.h * @param None * @retval None **********************************************************/ void L6474_SetDeviceParamsToPredefinedValues(void) { uint32_t i; devicePrm[0].acceleration = L6474_CONF_PARAM_ACC_DEVICE_0; devicePrm[0].deceleration = L6474_CONF_PARAM_DEC_DEVICE_0; devicePrm[0].maxSpeed = L6474_CONF_PARAM_MAX_SPEED_DEVICE_0; devicePrm[0].minSpeed = L6474_CONF_PARAM_MIN_SPEED_DEVICE_0; devicePrm[1].acceleration = L6474_CONF_PARAM_ACC_DEVICE_1; devicePrm[1].deceleration = L6474_CONF_PARAM_DEC_DEVICE_1; devicePrm[1].maxSpeed = L6474_CONF_PARAM_MAX_SPEED_DEVICE_1; devicePrm[1].minSpeed = L6474_CONF_PARAM_MIN_SPEED_DEVICE_1; devicePrm[2].acceleration = L6474_CONF_PARAM_ACC_DEVICE_2; devicePrm[2].deceleration = L6474_CONF_PARAM_DEC_DEVICE_2; devicePrm[2].maxSpeed = L6474_CONF_PARAM_MAX_SPEED_DEVICE_2; devicePrm[2].minSpeed = L6474_CONF_PARAM_MIN_SPEED_DEVICE_2; for (i = 0; i < MAX_NUMBER_OF_DEVICES; i++) { devicePrm[i].accu = 0; devicePrm[i].currentPosition = 0; devicePrm[i].endAccPos = 0; devicePrm[i].relativePos = 0; devicePrm[i].startDecPos = 0; devicePrm[i].stepsToTake = 0; devicePrm[i].speed = 0; devicePrm[i].commandExecuted = NO_CMD; devicePrm[i].direction = FORWARD; devicePrm[i].motionState = INACTIVE; } for (i = 0; i < numberOfDevices; i++) { L6474_SetRegisterToPredefinedValues(i); } } /******************************************************//** * @brief Initialises the bridge parameters to start the movement * and enable the power bridge * @param[in] deviceId (from 0 to 2) * @retval None **********************************************************/ void L6474_StartMovement(uint8_t deviceId) { #ifdef L6474_CONF_BRAKE_WHEN_HALTED /* Restore powerstage to full current capability */ switch (deviceId) { case 0: L6474_CmdSetParam(deviceId, L6474_TVAL, L6474_Tval_Current_to_Par(L6474_CONF_PARAM_TVAL_DEVICE_0)); break; case 1: L6474_CmdSetParam(deviceId, L6474_TVAL, L6474_Tval_Current_to_Par(L6474_CONF_PARAM_TVAL_DEVICE_1)); break; case 2: L6474_CmdSetParam(deviceId, L6474_TVAL, L6474_Tval_Current_to_Par(L6474_CONF_PARAM_TVAL_DEVICE_2)); break; default: ; } #endif /* Enable L6474 powerstage */ L6474_CmdEnable(deviceId); if (devicePrm[deviceId].endAccPos != 0) { devicePrm[deviceId].motionState = ACCELERATING; } else { devicePrm[deviceId].motionState = DECELERATING; } devicePrm[deviceId].accu = 0; devicePrm[deviceId].relativePos = 0; L6474_ApplySpeed(deviceId, devicePrm[deviceId].minSpeed); } /******************************************************//** * @brief Handles the device state machine at each ste * @param[in] deviceId (from 0 to 2) * @retval None * @note Must only be called by the timer ISR **********************************************************/ void L6474_StepClockHandler(uint8_t deviceId) { /* Set isr flag */ isrFlag = TRUE; /* Incrementation of the relative position */ devicePrm[deviceId].relativePos++; switch (devicePrm[deviceId].motionState) { case ACCELERATING: { uint32_t relPos = devicePrm[deviceId].relativePos; uint32_t endAccPos = devicePrm[deviceId].endAccPos; uint16_t speed = devicePrm[deviceId].speed; uint32_t acc = ((uint32_t)devicePrm[deviceId].acceleration << 16); if ((devicePrm[deviceId].commandExecuted == SOFT_STOP_CMD)|| ((devicePrm[deviceId].commandExecuted != RUN_CMD)&& (relPos == devicePrm[deviceId].startDecPos))) { devicePrm[deviceId].motionState = DECELERATING; devicePrm[deviceId].accu = 0; } else if ((speed >= devicePrm[deviceId].maxSpeed)|| ((devicePrm[deviceId].commandExecuted != RUN_CMD)&& (relPos == endAccPos))) { devicePrm[deviceId].motionState = STEADY; } else { bool speedUpdated = FALSE; /* Go on accelerating */ if (speed == 0) speed =1; devicePrm[deviceId].accu += acc / speed; while (devicePrm[deviceId].accu >= (0X10000L)) { devicePrm[deviceId].accu -= (0X10000L); speed +=1; speedUpdated = TRUE; } if (speedUpdated) { if (speed > devicePrm[deviceId].maxSpeed) { speed = devicePrm[deviceId].maxSpeed; } devicePrm[deviceId].speed = speed; L6474_ApplySpeed(deviceId, devicePrm[deviceId].speed); } } break; } case STEADY: { uint16_t maxSpeed = devicePrm[deviceId].maxSpeed; uint32_t relativePos = devicePrm[deviceId].relativePos; if ((devicePrm[deviceId].commandExecuted == SOFT_STOP_CMD)|| ((devicePrm[deviceId].commandExecuted != RUN_CMD)&& (relativePos >= (devicePrm[deviceId].startDecPos))) || ((devicePrm[deviceId].commandExecuted == RUN_CMD)&& (devicePrm[deviceId].speed > maxSpeed))) { devicePrm[deviceId].motionState = DECELERATING; devicePrm[deviceId].accu = 0; } else if ((devicePrm[deviceId].commandExecuted == RUN_CMD)&& (devicePrm[deviceId].speed < maxSpeed)) { devicePrm[deviceId].motionState = ACCELERATING; devicePrm[deviceId].accu = 0; } break; } case DECELERATING: { uint32_t relativePos = devicePrm[deviceId].relativePos; uint16_t speed = devicePrm[deviceId].speed; uint32_t deceleration = ((uint32_t)devicePrm[deviceId].deceleration << 16); if (((devicePrm[deviceId].commandExecuted == SOFT_STOP_CMD)&&(speed <= devicePrm[deviceId].minSpeed))|| ((devicePrm[deviceId].commandExecuted != RUN_CMD)&& (relativePos >= devicePrm[deviceId].stepsToTake))) { /* Motion process complete */ L6474_HardStop(deviceId); } else if ((devicePrm[deviceId].commandExecuted == RUN_CMD)&& (speed <= devicePrm[deviceId].maxSpeed)) { devicePrm[deviceId].motionState = STEADY; } else { /* Go on decelerating */ if (speed > devicePrm[deviceId].minSpeed) { bool speedUpdated = FALSE; if (speed == 0) speed =1; devicePrm[deviceId].accu += deceleration / speed; while (devicePrm[deviceId].accu >= (0X10000L)) { devicePrm[deviceId].accu -= (0X10000L); if (speed > 1) { speed -=1; } speedUpdated = TRUE; } if (speedUpdated) { if (speed < devicePrm[deviceId].minSpeed) { speed = devicePrm[deviceId].minSpeed; } devicePrm[deviceId].speed = speed; L6474_ApplySpeed(deviceId, devicePrm[deviceId].speed); } } } break; } default: { break; } } /* Set isr flag */ isrFlag = FALSE; } /******************************************************//** * @brief Converts mA in compatible values for TVAL register * @param[in] Tval * @retval TVAL values **********************************************************/ inline uint8_t L6474_Tval_Current_to_Par(double Tval) { return ((uint8_t)(((Tval - 31.25)/31.25)+0.5)); } /******************************************************//** * @brief Convert time in us in compatible values * for TON_MIN register * @param[in] Tmin * @retval TON_MIN values **********************************************************/ inline uint8_t L6474_Tmin_Time_to_Par(double Tmin) { return ((uint8_t)(((Tmin - 0.5)*2)+0.5)); } /******************************************************//** * @brief Write and receive a byte via SPI * @param[in] pByteToTransmit pointer to the byte to transmit * @param[in] pReceivedByte pointer to the received byte * @retval None **********************************************************/ void L6474_WriteBytes(uint8_t *pByteToTransmit, uint8_t *pReceivedByte) { if (BSP_MotorControlBoard_SpiWriteBytes(pByteToTransmit, pReceivedByte, numberOfDevices) != 0) { L6474_ErrorHandler(L6474_ERROR_1); } if (isrFlag) { spiPreemtionByIsr = TRUE; } } /** * @} */ /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/