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.
Diff: IHM01A1/l6474.cpp
- Revision:
- 0:b9444a40a999
- Child:
- 6:19c1b4a04c24
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/IHM01A1/l6474.cpp Sat Sep 05 20:18:14 2015 +0000 @@ -0,0 +1,1674 @@ +/** + ****************************************************************************** + * @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); + } + 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****/