Speed profile working

Fork of Easyspin_lib by Julien Tiron

Revision:
0:cba942f8172a
Child:
1:9efe863db15e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/easyspin.cpp	Tue Jul 07 20:35:36 2015 +0000
@@ -0,0 +1,1642 @@
+/******************************************************//**
+ * @file    easyspin.cpp 
+ * @version V1.0
+ * @date    June 29, 2015
+ * @brief   easyspin library for mbed
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either the GNU General Public License version 2
+ * or the GNU Lesser General Public License version 2.1, both as
+ * published by the Free Software Foundation.
+ **********************************************************/ 
+
+#include "easyspin.h"
+#include "mbed.h"
+
+#ifdef _DEBUG_Easyspin
+/// Log buffer
+char EasyspinStrOut[DEBUG_BUFFER_SIZE];
+#endif
+
+const uint16_t Easyspin::prescalerArrayTimer0_1[PRESCALER_ARRAY_TIMER0_1_SIZE] = { 0, 1, 8, 64, 256, 1024};
+const uint16_t Easyspin::prescalerArrayTimer2[PRESCALER_ARRAY_TIMER2_SIZE] = {0, 1, 8, 32, 64, 128, 256, 1024};
+volatile void (*Easyspin::flagInterruptCallback)(void);
+volatile uint8_t Easyspin::numberOfShields;
+uint8_t Easyspin::spiTxBursts[Easyspin_CMD_ARG_MAX_NB_BYTES][MAX_NUMBER_OF_SHIELDS];
+uint8_t Easyspin::spiRxBursts[Easyspin_CMD_ARG_MAX_NB_BYTES][MAX_NUMBER_OF_SHIELDS];
+volatile bool Easyspin::spiPreemtionByIsr = false;
+volatile bool Easyspin::isrFlag = false;
+volatile class Easyspin* Easyspin::instancePtr = NULL;
+  
+/******************************************************//**
+ * @brief  Constructor
+ * @param  None
+ * @retval None
+ **********************************************************/ 
+Easyspin::Easyspin():reset(Easyspin_Reset_Pin), dir1(Easyspin_DIR_1_Pin), dir2(Easyspin_DIR_2_Pin),
+                     dir3(Easyspin_DIR_3_Pin), CS(Easyspin_CS_Pin), flag(Easyspin_FLAG_Pin), pwm1(Easyspin_PWM_1_Pin), 
+                     pwm2(Easyspin_PWM_2_Pin), pwm3(Easyspin_PWM_3_Pin), spi(Easyspin_MOSI_Pin, Easyspin_MISO_Pin, Easyspin_SCK_Pin)
+{
+  uint8_t i;
+  for (i = 0; i < MAX_NUMBER_OF_SHIELDS; i++)
+  {
+    shieldPrm[i].motionState = INACTIVE;
+    shieldPrm[i].commandExecuted = NO_CMD;  
+    shieldPrm[i].stepsToTake = MAX_STEPS;
+  }
+    instancePtr = this;
+}
+
+/******************************************************//**
+ * @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 Easyspin::AttachFlagInterrupt(void (*callback)(void))
+{
+  flagInterruptCallback = (volatile void (*)())callback;
+}
+
+/******************************************************//**
+ * @brief Starts the Easyspin library
+ * @param[in] nbShields Number of Easyspin shields to use (from 1 to 3)
+ * @retval None
+ **********************************************************/
+void Easyspin::Begin(uint8_t nbShields)
+{
+  numberOfShields = nbShields;
+  
+  // start the SPI library:
+  //SPI.begin();
+  //SPI.setBitOrder(MSBFIRST);
+  spi.format(8, 3);
+  //SPI.setClockDivider(SPI_CLOCK_DIV4);
+  
+  // flag pin
+  //pinMode(Easyspin_FLAG_Pin, INPUT_PULLUP);
+  flag.fall(&FlagInterruptHandler);
+  
+  //reset pin
+  //pinMode(Easyspin_Reset_Pin, OUTPUT);
+  
+  switch (nbShields)
+  {
+    case 3:
+      //pinMode(Easyspin_DIR_3_Pin, OUTPUT);
+      //pinMode(Easyspin_PWM_3_Pin, OUTPUT);
+      PwmInit(2);
+    case 2:
+      //pinMode(Easyspin_DIR_2_Pin, OUTPUT);
+      //pinMode(Easyspin_PWM_2_Pin, OUTPUT);
+      PwmInit(1);
+    case 1:
+      //pinMode(Easyspin_DIR_1_Pin, OUTPUT);
+      //pinMode(Easyspin_PWM_1_Pin, OUTPUT);
+      PwmInit(0);
+    default:
+      ;
+  }
+  
+  /* Standby-reset deactivation */
+  ReleaseReset();
+  
+  /* Set all registers and context variables to the predefined values from Easyspin_target_config.h */
+  SetShieldParamsToPredefinedValues();
+  
+  /* Disable Easyspin powerstage */
+  for (uint32_t i = 0; i < nbShields; i++)
+  {
+    CmdDisable(i);
+    /* Get Status to clear flags after start up */
+    CmdGetStatus(i);
+  }
+}
+
+/******************************************************//**
+ * @brief Returns the acceleration of the specified shield
+ * @param[in] shieldId (from 0 to 2)
+ * @retval Acceleration in pps^2
+ **********************************************************/
+uint16_t Easyspin::GetAcceleration(uint8_t shieldId)
+{                                                  
+  return (shieldPrm[shieldId].acceleration);
+}            
+
+/******************************************************//**
+ * @brief Returns the current speed of the specified shield
+ * @param[in] shieldId (from 0 to 2)
+ * @retval Speed in pps
+ **********************************************************/
+uint16_t Easyspin::GetCurrentSpeed(uint8_t shieldId)
+{
+  return shieldPrm[shieldId].speed;
+}
+
+/******************************************************//**
+ * @brief Returns the deceleration of the specified shield
+ * @param[in] shieldId (from 0 to 2)
+ * @retval Deceleration in pps^2
+ **********************************************************/
+uint16_t Easyspin::GetDeceleration(uint8_t shieldId)
+{                                                  
+  return (shieldPrm[shieldId].deceleration);
+}          
+
+/******************************************************//**
+ * @brief Returns the FW version of the library
+ * @param None
+ * @retval Easyspin_FW_VERSION
+ **********************************************************/
+uint8_t Easyspin::GetFwVersion(void)
+{
+  return (Easyspin_FW_VERSION);
+}
+
+/******************************************************//**
+ * @brief  Returns the mark position  of the specified shield
+ * @param[in] shieldId (from 0 to 2)
+ * @retval Mark register value converted in a 32b signed integer 
+ **********************************************************/
+int32_t Easyspin::GetMark(uint8_t shieldId)
+{
+  return ConvertPosition(CmdGetParam(shieldId,Easyspin_MARK));
+}
+
+/******************************************************//**
+ * @brief  Returns the max speed of the specified shield
+ * @param[in] shieldId (from 0 to 2)
+ * @retval maxSpeed in pps
+ **********************************************************/
+uint16_t Easyspin::GetMaxSpeed(uint8_t shieldId)
+{                                                  
+  return (shieldPrm[shieldId].maxSpeed);
+}                                                     
+
+/******************************************************//**
+ * @brief  Returns the min speed of the specified shield
+ * @param[in] shieldId (from 0 to 2)
+ * @retval minSpeed in pps
+ **********************************************************/
+uint16_t Easyspin::GetMinSpeed(uint8_t shieldId)
+{                                                  
+  return (shieldPrm[shieldId].minSpeed);
+}                                                     
+
+/******************************************************//**
+ * @brief  Returns the ABS_POSITION of the specified shield
+ * @param[in] shieldId (from 0 to 2)
+ * @retval ABS_POSITION register value converted in a 32b signed integer
+ **********************************************************/
+int32_t Easyspin::GetPosition(uint8_t shieldId)
+{
+  return ConvertPosition(CmdGetParam(shieldId,Easyspin_ABS_POS));
+}
+
+/******************************************************//**
+ * @brief Returns the shield state
+ * @param[in] shieldId (from 0 to 2)
+ * @retval State (ACCELERATING, DECELERATING, STEADY or INACTIVE)
+ **********************************************************/
+shieldState_t Easyspin::GetShieldState(uint8_t shieldId)
+{
+  return shieldPrm[shieldId].motionState;
+}
+
+/******************************************************//**
+ * @brief  Requests the motor to move to the home position (ABS_POSITION = 0)
+ * @param[in] shieldId (from 0 to 2)
+ * @retval None
+ **********************************************************/
+void Easyspin::GoHome(uint8_t shieldId)
+{
+  GoTo(shieldId, 0);
+} 
+  
+/******************************************************//**
+ * @brief  Requests the motor to move to the mark position 
+ * @param[in] shieldId (from 0 to 2)
+ * @retval None
+ **********************************************************/
+void Easyspin::GoMark(uint8_t shieldId)
+{
+    uint32_t mark;
+
+    mark = ConvertPosition(CmdGetParam(shieldId,Easyspin_MARK));
+    GoTo(shieldId,mark);  
+}
+
+/******************************************************//**
+ * @brief  Requests the motor to move to the specified position 
+ * @param[in] shieldId (from 0 to 2)
+ * @param[in] targetPosition absolute position in steps
+ * @retval None
+ **********************************************************/
+void Easyspin::GoTo(uint8_t shieldId, int32_t targetPosition)
+{
+  dir_t direction;
+  int32_t steps;
+  
+  /* Eventually deactivate motor */
+  if (shieldPrm[shieldId].motionState != INACTIVE) 
+  {
+    HardStop(shieldId);
+  }
+
+  /* Get current position */
+  shieldPrm[shieldId].currentPosition = ConvertPosition(CmdGetParam(shieldId,Easyspin_ABS_POS));
+  
+  /* Compute the number of steps to perform */
+  steps = targetPosition - shieldPrm[shieldId].currentPosition;
+  
+  if (steps >= 0) 
+  {
+    shieldPrm[shieldId].stepsToTake = steps;
+    direction = FORWARD;
+    
+  } 
+  else 
+  {
+    shieldPrm[shieldId].stepsToTake = -steps;
+    direction = BACKWARD;
+  }
+  
+  if (steps != 0) 
+  {
+    
+    shieldPrm[shieldId].commandExecuted = MOVE_CMD;
+        
+    /* Direction setup */
+    SetDirection(shieldId,direction);
+
+    ComputeSpeedProfile(shieldId, shieldPrm[shieldId].stepsToTake);
+    
+    /* Motor activation */
+    StartMovement(shieldId);
+  }  
+}
+
+/******************************************************//**
+ * @brief  Immediatly stops the motor and disable the power bridge
+ * @param[in] shieldId (from 0 to 2)
+ * @retval None
+ **********************************************************/
+void Easyspin::HardStop(uint8_t shieldId) 
+{
+  /* Disable corresponding PWM */
+  PwmStop(shieldId);
+
+  /* Disable power stage */
+  CmdDisable(shieldId);
+
+  /* Set inactive state */
+  shieldPrm[shieldId].motionState = INACTIVE;
+  shieldPrm[shieldId].commandExecuted = NO_CMD;
+  shieldPrm[shieldId].stepsToTake = MAX_STEPS;  
+
+#ifdef _DEBUG_Easyspin
+ Serial.println("Inactive\n");
+#endif     
+}
+
+/******************************************************//**
+ * @brief  Moves the motor of the specified number of steps
+ * @param[in] shieldId (from 0 to 2)
+ * @param[in] direction FORWARD or BACKWARD
+ * @param[in] stepCount Number of steps to perform
+ * @retval None
+ **********************************************************/
+void Easyspin::Move(uint8_t shieldId, dir_t direction, uint32_t stepCount)
+{
+  /* Eventually deactivate motor */
+  if (shieldPrm[shieldId].motionState != INACTIVE) 
+  {
+    HardStop(shieldId);
+  }
+  
+  if (stepCount != 0) 
+  {
+    shieldPrm[shieldId].stepsToTake = stepCount;
+    
+    shieldPrm[shieldId].commandExecuted = MOVE_CMD;
+    
+    shieldPrm[shieldId].currentPosition = ConvertPosition(CmdGetParam(shieldId,Easyspin_ABS_POS));
+    
+    /* Direction setup */
+    SetDirection(shieldId,direction);
+
+    ComputeSpeedProfile(shieldId, stepCount);
+    
+    /* Motor activation */
+    StartMovement(shieldId);
+  }  
+}
+
+/******************************************************//**
+ * @brief Resets all Easyspin shields
+ * @param None
+ * @retval None
+ **********************************************************/
+void Easyspin::ResetAllShields(void)
+{
+    uint8_t loop;
+    
+    for (loop = 0; loop < numberOfShields; loop++)
+    {
+    /* Stop movement and disable power stage*/
+    HardStop(loop);
+  }
+    Reset();
+    WaitUs(20); // Reset pin must be forced low for at least 10us
+    ReleaseReset();
+}
+
+/******************************************************//**
+ * @brief  Runs the motor. It will accelerate from the min 
+ * speed up to the max speed by using the shield acceleration.
+ * @param[in] shieldId (from 0 to 2)
+ * @param[in] direction FORWARD or BACKWARD
+ * @retval None
+ **********************************************************/
+void Easyspin::Run(uint8_t shieldId, dir_t direction)
+{
+  /* Eventually deactivate motor */
+  if (shieldPrm[shieldId].motionState != INACTIVE) 
+  {
+    HardStop(shieldId);
+  }
+  
+    /* Direction setup */
+    SetDirection(shieldId,direction);
+
+    shieldPrm[shieldId].commandExecuted = RUN_CMD;
+
+    /* Motor activation */
+    StartMovement(shieldId); 
+}
+
+/******************************************************//**
+ * @brief  Changes the acceleration of the specified shield
+ * @param[in] shieldId (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 shield is executing 
+ * a MOVE or GOTO command (but it can be used during a RUN command)
+ **********************************************************/
+bool Easyspin::SetAcceleration(uint8_t shieldId,uint16_t newAcc)
+{                                                  
+  bool cmdExecuted = false;
+  if ((newAcc != 0)&&
+      ((shieldPrm[shieldId].motionState == INACTIVE)||
+       (shieldPrm[shieldId].commandExecuted == RUN_CMD)))
+  {
+    shieldPrm[shieldId].acceleration = newAcc;
+    cmdExecuted = true;
+  }    
+  return cmdExecuted;
+}            
+
+/******************************************************//**
+ * @brief  Changes the deceleration of the specified shield
+ * @param[in] shieldId (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 shield is executing 
+ * a MOVE or GOTO command (but it can be used during a RUN command)
+ **********************************************************/
+bool Easyspin::SetDeceleration(uint8_t shieldId, uint16_t newDec)
+{                                                  
+  bool cmdExecuted = false;
+  if ((newDec != 0)&& 
+      ((shieldPrm[shieldId].motionState == INACTIVE)||
+       (shieldPrm[shieldId].commandExecuted == RUN_CMD)))
+  {
+    shieldPrm[shieldId].deceleration = newDec;
+    cmdExecuted = true;
+  }      
+  return cmdExecuted;
+}        
+
+/******************************************************//**
+ * @brief  Set current position to be the Home position (ABS pos set to 0)
+ * @param[in] shieldId (from 0 to 2)
+ * @retval None
+ **********************************************************/
+void Easyspin::SetHome(uint8_t shieldId)
+{
+  CmdSetParam(shieldId, Easyspin_ABS_POS, 0);
+}
+ 
+/******************************************************//**
+ * @brief  Sets current position to be the Mark position 
+ * @param[in] shieldId (from 0 to 2)
+ * @retval None
+ **********************************************************/
+void Easyspin::SetMark(uint8_t shieldId)
+{
+  uint32_t mark = CmdGetParam(shieldId,Easyspin_ABS_POS);
+  CmdSetParam(shieldId,Easyspin_MARK, mark);
+}
+
+/******************************************************//**
+ * @brief  Changes the max speed of the specified shield
+ * @param[in] shieldId (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 shield is executing 
+ * a MOVE or GOTO command (but it can be used during a RUN command).
+ **********************************************************/
+bool Easyspin::SetMaxSpeed(uint8_t shieldId, uint16_t newMaxSpeed)
+{                                                  
+  bool cmdExecuted = false;
+  if ((newMaxSpeed > Easyspin_MIN_PWM_FREQ)&&
+      (newMaxSpeed <= Easyspin_MAX_PWM_FREQ) &&
+      (shieldPrm[shieldId].minSpeed <= newMaxSpeed) &&
+      ((shieldPrm[shieldId].motionState == INACTIVE)||
+       (shieldPrm[shieldId].commandExecuted == RUN_CMD)))
+  {
+    shieldPrm[shieldId].maxSpeed = newMaxSpeed;
+    cmdExecuted = true;
+  }
+  return cmdExecuted;
+}                                                     
+
+/******************************************************//**
+ * @brief  Changes the min speed of the specified shield
+ * @param[in] shieldId (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 shield is executing 
+ * a MOVE or GOTO command (but it can be used during a RUN command).
+ **********************************************************/
+bool Easyspin::SetMinSpeed(uint8_t shieldId, uint16_t newMinSpeed)
+{                                                  
+  bool cmdExecuted = false;
+  if ((newMinSpeed >= Easyspin_MIN_PWM_FREQ)&&
+      (newMinSpeed < Easyspin_MAX_PWM_FREQ) &&
+      (newMinSpeed <= shieldPrm[shieldId].maxSpeed) && 
+      ((shieldPrm[shieldId].motionState == INACTIVE)||
+       (shieldPrm[shieldId].commandExecuted == RUN_CMD)))
+  {
+    shieldPrm[shieldId].minSpeed = newMinSpeed;
+    cmdExecuted = true;
+  }  
+  return cmdExecuted;
+}                 
+
+/******************************************************//**
+ * @brief  Stops the motor by using the shield deceleration
+ * @param[in] shieldId (from 0 to 2)
+ * @retval true if the command is successfully executed, else false
+ * @note The command is not performed is the shield is in INACTIVE state.
+ **********************************************************/
+bool Easyspin::SoftStop(uint8_t shieldId)
+{   
+  bool cmdExecuted = false;
+  if (shieldPrm[shieldId].motionState != INACTIVE)
+  {
+    shieldPrm[shieldId].commandExecuted = SOFT_STOP_CMD;
+    cmdExecuted = true;
+  }
+  return (cmdExecuted);
+}
+
+/******************************************************//**
+ * @brief  Locks until the shield state becomes Inactive
+ * @param[in] shieldId (from 0 to 2)
+ * @retval None
+ **********************************************************/
+void Easyspin::WaitWhileActive(uint8_t shieldId)
+ {
+    /* Wait while motor is running */
+    while (GetShieldState(shieldId) != INACTIVE);
+}
+
+/******************************************************//**
+ * @brief  Issue the Disable command to the Easyspin of the specified shield
+ * @param[in] shieldId (from 0 to 2)
+ * @retval None
+ **********************************************************/
+void Easyspin::CmdDisable(uint8_t shieldId)
+{
+  SendCommand(shieldId, Easyspin_DISABLE);
+}
+
+/******************************************************//**
+ * @brief  Issues the Enable command to the Easyspin of the specified shield
+ * @param[in] shieldId (from 0 to 2)
+ * @retval None
+ **********************************************************/
+void Easyspin::CmdEnable(uint8_t shieldId)
+{
+  SendCommand(shieldId, Easyspin_ENABLE);
+}
+
+/******************************************************//**
+ * @brief  Issues the GetParam command to the Easyspin of the specified shield
+ * @param[in] shieldId (from 0 to 2)
+ * @param[in] param Register adress (Easyspin_ABS_POS, Easyspin_MARK,...)
+ * @retval Register value
+ **********************************************************/
+uint32_t Easyspin::CmdGetParam(uint8_t shieldId, Easyspin_Registers_t param)
+{
+  uint32_t i;
+  uint32_t spiRxData;
+  uint8_t maxArgumentNbBytes = 0;
+  uint8_t spiIndex = numberOfShields - shieldId - 1;
+  bool itDisable = false;  
+  
+  do
+  {
+    spiPreemtionByIsr = false;
+    if (itDisable)
+    {
+      /* re-enable interrupts if disable in previous iteration */
+      flag.enable_irq();
+      itDisable = false;
+    }
+  
+    for (i = 0; i < numberOfShields; i++)
+    {
+      spiTxBursts[0][i] = Easyspin_NOP;
+      spiTxBursts[1][i] = Easyspin_NOP;
+      spiTxBursts[2][i] = Easyspin_NOP;
+      spiTxBursts[3][i] = Easyspin_NOP;
+      spiRxBursts[1][i] = 0;
+      spiRxBursts[2][i] = 0;
+      spiRxBursts[3][i] = 0;    
+    }
+    switch (param)
+    {
+      case Easyspin_ABS_POS: ;
+      case Easyspin_MARK:
+        spiTxBursts[0][spiIndex] = ((uint8_t)Easyspin_GET_PARAM )| (param);
+        maxArgumentNbBytes = 3;
+        break;
+      case Easyspin_EL_POS: ;
+      case Easyspin_CONFIG: ;
+      case Easyspin_STATUS:
+        spiTxBursts[1][spiIndex] = ((uint8_t)Easyspin_GET_PARAM )| (param);
+        maxArgumentNbBytes = 2;
+        break;
+      default:
+        spiTxBursts[2][spiIndex] = ((uint8_t)Easyspin_GET_PARAM )| (param);
+        maxArgumentNbBytes = 1;
+    }
+    
+    /* Disable interruption before checking */
+    /* pre-emption by ISR and SPI transfers*/
+    flag.disable_irq();
+    itDisable = true;
+  } while (spiPreemtionByIsr); // check pre-emption by ISR
+    
+  for (i = Easyspin_CMD_ARG_MAX_NB_BYTES-1-maxArgumentNbBytes;
+       i < Easyspin_CMD_ARG_MAX_NB_BYTES;
+       i++)
+  {
+     WriteBytes(&spiTxBursts[i][0],
+                          &spiRxBursts[i][0]);
+  }
+  
+  spiRxData = ((uint32_t)spiRxBursts[1][spiIndex] << 16)|
+              (spiRxBursts[2][spiIndex] << 8) |
+              (spiRxBursts[3][spiIndex]);
+  
+  /* re-enable interrupts after SPI transfers*/
+  flag.enable_irq();
+    
+  return (spiRxData);
+}
+
+/******************************************************//**
+ * @brief  Issues the GetStatus command to the Easyspin of the specified shield
+ * @param[in] shieldId (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 ReadStatusRegister or CmdGetParam).
+ **********************************************************/
+uint16_t Easyspin::CmdGetStatus(uint8_t shieldId)
+{
+  uint32_t i;
+  uint16_t status;
+  uint8_t spiIndex = numberOfShields - shieldId - 1;
+  bool itDisable = false;  
+  
+  do
+  {
+    spiPreemtionByIsr = false;
+    if (itDisable)
+    {
+      /* re-enable interrupts if disable in previous iteration */
+      flag.enable_irq();
+      itDisable = false;
+    }
+
+    for (i = 0; i < numberOfShields; i++)
+    {
+       spiTxBursts[0][i] = Easyspin_NOP;
+       spiTxBursts[1][i] = Easyspin_NOP;
+       spiTxBursts[2][i] = Easyspin_NOP;
+       spiRxBursts[1][i] = 0;
+       spiRxBursts[2][i] = 0;
+    }
+    spiTxBursts[0][spiIndex] = Easyspin_GET_STATUS;
+
+    /* Disable interruption before checking */
+    /* pre-emption by ISR and SPI transfers*/
+    flag.disable_irq();
+    itDisable = true;
+  } while (spiPreemtionByIsr); // check pre-emption by ISR
+
+  for (i = 0; i < Easyspin_CMD_ARG_NB_BYTES_GET_STATUS + Easyspin_RSP_NB_BYTES_GET_STATUS; i++)
+  {
+     WriteBytes(&spiTxBursts[i][0], &spiRxBursts[i][0]);
+  }
+  status = (spiRxBursts[1][spiIndex] << 8) | (spiRxBursts[2][spiIndex]);
+  
+  /* re-enable interrupts after SPI transfers*/
+  flag.enable_irq();
+  
+  return (status);
+}
+
+/******************************************************//**
+ * @brief  Issues the Nop command to the Easyspin of the specified shield
+ * @param[in] shieldId (from 0 to 2)
+ * @retval None
+ **********************************************************/
+void Easyspin::CmdNop(uint8_t shieldId)
+{
+  SendCommand(shieldId, Easyspin_NOP);
+}
+
+/******************************************************//**
+ * @brief  Issues the SetParam command to the Easyspin of the specified shield
+ * @param[in] shieldId (from 0 to 2)
+ * @param[in] param Register adress (Easyspin_ABS_POS, Easyspin_MARK,...)
+ * @param[in] value Value to set in the register
+ * @retval None
+ **********************************************************/
+void Easyspin::CmdSetParam(uint8_t shieldId,
+                        Easyspin_Registers_t param,
+                        uint32_t value)
+{
+  uint32_t i;
+  uint8_t maxArgumentNbBytes = 0;
+  uint8_t spiIndex = numberOfShields - shieldId - 1;
+  bool itDisable = false;  
+  do
+  {
+    spiPreemtionByIsr = false;
+    if (itDisable)
+    {
+      /* re-enable interrupts if disable in previous iteration */
+      flag.enable_irq();//interrupts();
+      itDisable = false;
+    }
+    for (i = 0; i < numberOfShields; i++)
+    {
+      spiTxBursts[0][i] = Easyspin_NOP;
+      spiTxBursts[1][i] = Easyspin_NOP;
+      spiTxBursts[2][i] = Easyspin_NOP;
+      spiTxBursts[3][i] = Easyspin_NOP;
+    }
+    switch (param)
+  {
+    case Easyspin_ABS_POS: ;
+    case Easyspin_MARK:
+        spiTxBursts[0][spiIndex] = param;
+        spiTxBursts[1][spiIndex] = (uint8_t)(value >> 16);
+        spiTxBursts[2][spiIndex] = (uint8_t)(value >> 8);
+        maxArgumentNbBytes = 3;
+        break;
+    case Easyspin_EL_POS: ;
+    case Easyspin_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*/
+    flag.disable_irq();
+    itDisable = true;
+  } while (spiPreemtionByIsr); // check pre-emption by ISR
+ 
+  /* SPI transfer */
+  for (i = Easyspin_CMD_ARG_MAX_NB_BYTES-1-maxArgumentNbBytes;
+       i < Easyspin_CMD_ARG_MAX_NB_BYTES;
+       i++)
+  {
+     WriteBytes(&spiTxBursts[i][0],&spiRxBursts[i][0]);
+  }
+  /* re-enable interrupts after SPI transfers*/
+  flag.enable_irq();
+}
+
+/******************************************************//**
+ * @brief  Reads the Status Register value
+ * @param[in] shieldId (from 0 to 2)
+ * @retval Status register valued
+ * @note The status register flags are not cleared 
+ * at the difference with CmdGetStatus()
+ **********************************************************/
+uint16_t Easyspin::ReadStatusRegister(uint8_t shieldId)
+{
+  return (CmdGetParam(shieldId,Easyspin_STATUS));
+}
+
+/******************************************************//**
+ * @brief  Releases the Easyspin reset (pin set to High) of all shields
+ * @param  None
+ * @retval None
+ **********************************************************/
+void Easyspin::ReleaseReset(void)
+{ 
+  reset = 1;
+}
+
+/******************************************************//**
+ * @brief  Resets the Easyspin (reset pin set to low) of all shields
+ * @param  None
+ * @retval None
+ **********************************************************/
+void Easyspin::Reset(void)
+{
+  reset = 0;
+}
+
+/******************************************************//**
+ * @brief  Set the stepping mode 
+ * @param[in] shieldId (from 0 to 2)
+ * @param[in] stepMod from full step to 1/16 microstep as specified in enum Easyspin_STEP_SEL_t
+ * @retval None
+ **********************************************************/
+void Easyspin::SelectStepMode(uint8_t shieldId, Easyspin_STEP_SEL_t stepMod)
+{
+  uint8_t stepModeRegister;
+  
+  /* Eventually deactivate motor */
+  if (shieldPrm[shieldId].motionState != INACTIVE) 
+  {
+    HardStop(shieldId);
+  }
+  
+  /* Read Step mode register and clear STEP_SEL field */
+  stepModeRegister = (uint8_t)(0xF8 & CmdGetParam(shieldId,Easyspin_STEP_MODE)) ;
+  
+  /* Apply new step mode */
+  CmdSetParam(shieldId, Easyspin_STEP_MODE, stepModeRegister | (uint8_t)stepMod);
+
+  /* Reset abs pos register */
+  SetHome(shieldId);
+}
+
+/******************************************************//**
+ * @brief  Specifies the direction 
+ * @param[in] shieldId (from 0 to 2)
+ * @param[in] dir FORWARD or BACKWARD
+ * @note The direction change is only applied if the shield 
+ * is in INACTIVE state
+ * @retval None
+ **********************************************************/
+void Easyspin::SetDirection(uint8_t shieldId, dir_t dir)
+{
+  if (shieldPrm[shieldId].motionState == INACTIVE)
+  {
+    shieldPrm[shieldId].direction = dir;
+    
+    switch (shieldId)
+    {
+      case 2:
+        dir3 = dir;
+        break;
+      case 1:
+        dir2 = dir;
+        break;
+      case 0:
+        dir1 = dir;
+        break;
+      default:
+        ;
+    }
+  }
+}
+
+/******************************************************//**
+ * @brief  Waits for the specify delay in milliseconds
+ * @param[in] msDelay delay in milliseconds
+ * @retval None
+ * @note Should only be used for 3 shields configuration.
+ * Else, prefer the standard Arduino function delay().
+ **********************************************************/
+void Easyspin::WaitMs(uint16_t msDelay)
+{
+  uint16_t i;
+  for (i = 0; i < msDelay ; i++)
+  {
+    WaitUs(1000);
+  }
+}
+
+/******************************************************//**
+ * @brief  Waits for the specify delay in microseconds
+ * @param[in] usDelay delay in microseconds
+ * @retval None
+ * @note Should be only used for 3 shields configuration.
+ * Else, prefer the standard Arduino function delayMicroseconds().
+ * Besides, this function is a copy of delayMicroseconds inside
+ * the Easyspin library to avoid dependencies conflicts 
+ * (a redefinition of ISR(TIMER0_OVF_vect)). 
+ **********************************************************/
+void Easyspin::WaitUs(uint16_t usDelay)
+{
+    // calling avrlib's delay_us() function with low values (e.g. 1 or
+    // 2 microseconds) gives delays longer than desired.
+    //delay_us(us);
+#if F_CPU >= 20000000L
+    // for the 20 MHz clock on rare Arduino boards
+
+    // for a one-microsecond delay, simply wait 2 cycle and return. The overhead
+    // of the function call yields a delay of exactly a one microsecond.
+    __asm__ __volatile__ (
+        "nop" "\n\t"
+        "nop"); //just waiting 2 cycle
+    if (--usDelay == 0)
+        return;
+
+    // the following loop takes a 1/5 of a microsecond (4 cycles)
+    // per iteration, so execute it five times for each microsecond of
+    // delay requested.
+    usDelay = (usDelay<<2) + usDelay; // x5 us
+
+    // account for the time taken in the preceeding commands.
+    usDelay -= 2;
+
+#elif F_CPU >= 16000000L
+    // for the 16 MHz clock on most Arduino boards
+
+    // for a one-microsecond delay, simply return.  the overhead
+    // of the function call yields a delay of approximately 1 1/8 us.
+    if (--usDelay == 0)
+        return;
+
+    // the following loop takes a quarter of a microsecond (4 cycles)
+    // per iteration, so execute it four times for each microsecond of
+    // delay requested.
+    usDelay <<= 2;
+
+    // account for the time taken in the preceeding commands.
+    usDelay -= 2;
+#else
+    // for the 8 MHz internal clock on the ATmega168
+
+    // for a one- or two-microsecond delay, simply return.  the overhead of
+    // the function calls takes more than two microseconds.  can't just
+    // subtract two, since us is unsigned; we'd overflow.
+    if (--usDelay == 0)
+        return;
+    if (--usDelay == 0)
+        return;
+
+    // the following loop takes half of a microsecond (4 cycles)
+    // per iteration, so execute it twice for each microsecond of
+    // delay requested.
+    usDelay <<= 1;
+    
+    // partially compensate for the time taken by the preceeding commands.
+    // we can't subtract any more than this or we'd overflow w/ small delays.
+    usDelay--;
+#endif
+}  
+                  
+/******************************************************//**
+ * @brief  Gets the pointer to the Easyspin instance
+ * @param  None
+ * @retval Pointer to the instance of Easyspin
+  **********************************************************/
+class Easyspin* Easyspin::GetInstancePtr(void)
+{
+  return (class Easyspin*)instancePtr;
+}
+
+/******************************************************//**
+ * @brief  Handles the shield state machine at each ste
+ * @param[in] shieldId (from 0 to 2)
+ * @retval None
+ * @note Must only be called by the timer ISR
+ **********************************************************/
+void Easyspin::StepClockHandler(uint8_t shieldId)
+{
+  /* Set isr flag */
+  isrFlag = true;
+  
+  /* Incrementation of the relative position */
+  shieldPrm[shieldId].relativePos++;
+  
+  /* Periodically check that estimated position is correct */
+  if ((shieldPrm[shieldId].commandExecuted != RUN_CMD) && 
+      ((shieldPrm[shieldId].relativePos % 10) == 00))
+  {
+    uint32_t AbsPos= ConvertPosition(CmdGetParam(shieldId,Easyspin_ABS_POS));
+  
+    /* Correct estimated position if needed */
+    if (AbsPos != 0)
+    {  
+      if ((shieldPrm[shieldId].direction == FORWARD) && 
+          (AbsPos != shieldPrm[shieldId].currentPosition + shieldPrm[shieldId].relativePos))
+      {
+#ifdef _DEBUG_Easyspin
+        snprintf(EasyspinStrOut, DEBUG_BUFFER_SIZE, "F EstPos:%ld RealPos: %ld\n",shieldPrm[shieldId].relativePos,(AbsPos - shieldPrm[shieldId].currentPosition));
+        Serial.println(EasyspinStrOut);  
+#endif                
+        shieldPrm[shieldId].relativePos = AbsPos - shieldPrm[shieldId].currentPosition;
+        
+      }
+      else if ((shieldPrm[shieldId].direction == BACKWARD) && 
+               (AbsPos != shieldPrm[shieldId].currentPosition - shieldPrm[shieldId].relativePos))
+      {
+#ifdef _DEBUG_Easyspin
+        snprintf(EasyspinStrOut, DEBUG_BUFFER_SIZE, "B EstPos:%ld RealPos: %ld\n",shieldPrm[shieldId].relativePos,(AbsPos - shieldPrm[shieldId].currentPosition));
+        Serial.println(EasyspinStrOut);  
+#endif        
+        shieldPrm[shieldId].relativePos = shieldPrm[shieldId].currentPosition - AbsPos;
+      }
+    }
+  }
+ 
+  switch (shieldPrm[shieldId].motionState) 
+  {
+    case ACCELERATING: 
+    {
+        if ((shieldPrm[shieldId].commandExecuted == SOFT_STOP_CMD)||
+            ((shieldPrm[shieldId].commandExecuted != RUN_CMD)&&  
+             (shieldPrm[shieldId].relativePos == shieldPrm[shieldId].startDecPos)))
+        {
+          shieldPrm[shieldId].motionState = DECELERATING;
+          shieldPrm[shieldId].accu = 0;
+#ifdef _DEBUG_Easyspin
+          snprintf(EasyspinStrOut, DEBUG_BUFFER_SIZE, "Acc->Dec: speed: %u relativepos: %ld \n",shieldPrm[shieldId].speed,shieldPrm[shieldId].relativePos);
+          Serial.println(EasyspinStrOut);  
+#endif    
+        }
+        else if ((shieldPrm[shieldId].speed >= shieldPrm[shieldId].maxSpeed)||
+                 ((shieldPrm[shieldId].commandExecuted != RUN_CMD)&&
+                  (shieldPrm[shieldId].relativePos == shieldPrm[shieldId].endAccPos)))
+        {
+          shieldPrm[shieldId].motionState = STEADY;
+#ifdef _DEBUG_Easyspin
+        snprintf(EasyspinStrOut, DEBUG_BUFFER_SIZE, "Acc->Steady: speed: %u relativepos: %ld \n",shieldPrm[shieldId].speed,shieldPrm[shieldId].relativePos);
+        Serial.println(EasyspinStrOut);  
+#endif    
+        }
+        else
+        {
+          bool speedUpdated = false;
+          /* Go on accelerating */
+          shieldPrm[shieldId].accu += ((uint32_t)shieldPrm[shieldId].acceleration << 16) / shieldPrm[shieldId].speed;
+          while (shieldPrm[shieldId].accu >= (0X10000L))
+          {
+            shieldPrm[shieldId].accu -= (0X10000L);
+            shieldPrm[shieldId].speed +=1;
+            speedUpdated = true;
+          }
+          
+          if (speedUpdated)
+          {
+            ApplySpeed(shieldId, shieldPrm[shieldId].speed);
+          }
+        }
+        break;
+    }
+    case STEADY: 
+    {
+      if  ((shieldPrm[shieldId].commandExecuted == SOFT_STOP_CMD)||
+           ((shieldPrm[shieldId].commandExecuted != RUN_CMD)&&
+            (shieldPrm[shieldId].relativePos >= (shieldPrm[shieldId].startDecPos))) ||
+           ((shieldPrm[shieldId].commandExecuted == RUN_CMD)&&
+            (shieldPrm[shieldId].speed > shieldPrm[shieldId].maxSpeed)))
+      {
+        shieldPrm[shieldId].motionState = DECELERATING;
+        shieldPrm[shieldId].accu = 0;
+      }
+      else if ((shieldPrm[shieldId].commandExecuted == RUN_CMD)&&
+               (shieldPrm[shieldId].speed < shieldPrm[shieldId].maxSpeed))
+      {
+        shieldPrm[shieldId].motionState = ACCELERATING;
+        shieldPrm[shieldId].accu = 0;
+      }
+      break;
+    }
+    case DECELERATING: 
+    {
+      if (((shieldPrm[shieldId].commandExecuted == SOFT_STOP_CMD)&&(shieldPrm[shieldId].speed <=  shieldPrm[shieldId].minSpeed))||
+          ((shieldPrm[shieldId].commandExecuted != RUN_CMD)&&
+           (shieldPrm[shieldId].relativePos >= shieldPrm[shieldId].stepsToTake)))
+      {
+        /* Motion process complete */
+        HardStop(shieldId);
+#ifdef _DEBUG_Easyspin
+        snprintf(EasyspinStrOut, DEBUG_BUFFER_SIZE, "Dec->Stop: speed: %u relativepos: %ld \n",shieldPrm[shieldId].speed,shieldPrm[shieldId].relativePos );
+        Serial.println(EasyspinStrOut);  
+#endif   
+      }
+      else if ((shieldPrm[shieldId].commandExecuted == RUN_CMD)&&
+               (shieldPrm[shieldId].speed <= shieldPrm[shieldId].maxSpeed))
+      {
+        shieldPrm[shieldId].motionState = STEADY;
+#ifdef _DEBUG_Easyspin
+        snprintf(EasyspinStrOut, DEBUG_BUFFER_SIZE, "Dec->Steady: speed: %u relativepos: %ld \n",shieldPrm[shieldId].speed,shieldPrm[shieldId].relativePos);
+        Serial.println(EasyspinStrOut);  
+#endif            
+      }
+      else
+      {
+        /* Go on decelerating */
+        if (shieldPrm[shieldId].speed > shieldPrm[shieldId].minSpeed)
+        {
+          bool speedUpdated = false;
+          shieldPrm[shieldId].accu += ((uint32_t)shieldPrm[shieldId].deceleration << 16) / shieldPrm[shieldId].speed;
+          while (shieldPrm[shieldId].accu >= (0X10000L))
+          {
+            shieldPrm[shieldId].accu -= (0X10000L);
+            shieldPrm[shieldId].speed -=1;
+            speedUpdated = true;
+          }
+          if (speedUpdated)
+          {
+            ApplySpeed(shieldId, shieldPrm[shieldId].speed);
+          }
+        }
+      }
+      break;
+    }
+    default: 
+    {
+      break;
+    }
+  }  
+  /* Set isr flag */
+  isrFlag = false;
+}
+
+/******************************************************//**
+ * @brief  Updates the current speed of the shield
+ * @param[in] shieldId (from 0 to 2)
+ * @param[in] newSpeed in pps
+ * @retval None
+ **********************************************************/
+void Easyspin::ApplySpeed(uint8_t shieldId, uint16_t newSpeed)
+{
+  if (newSpeed < Easyspin_MIN_PWM_FREQ)
+  {
+    newSpeed = Easyspin_MIN_PWM_FREQ;  
+  }
+  if (newSpeed > Easyspin_MAX_PWM_FREQ)
+  {
+    newSpeed = Easyspin_MAX_PWM_FREQ;
+  }
+  
+  shieldPrm[shieldId].speed = newSpeed;
+
+  switch (shieldId)
+  {
+    case  0:
+      Pwm1SetFreq(newSpeed);
+      break;
+    case 1:
+      Pwm2SetFreq(newSpeed);
+      break;
+    case 2:
+      Pwm3SetFreq(newSpeed);
+      break;
+    default:
+      break; //ignore error
+  }
+}
+
+/******************************************************//**
+ * @brief  Computes the speed profile according to the number of steps to move
+ * @param[in] shieldId (from 0 to 2)
+ * @param[in] nbSteps number of steps to perform
+ * @retval None
+ * @note Using the acceleration and deceleration of the shield,
+ * 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 Easyspin::ComputeSpeedProfile(uint8_t shieldId, uint32_t nbSteps)
+{
+  uint32_t reqAccSteps; 
+    uint32_t reqDecSteps;
+   
+  /* compute the number of steps to get the targeted speed */
+  reqAccSteps = (shieldPrm[shieldId].maxSpeed - shieldPrm[shieldId].minSpeed);
+  reqAccSteps *= (shieldPrm[shieldId].maxSpeed + shieldPrm[shieldId].minSpeed);
+  reqDecSteps = reqAccSteps;
+  reqAccSteps /= (uint32_t)shieldPrm[shieldId].acceleration;
+  reqAccSteps /= 2;
+
+  /* compute the number of steps to stop */
+  reqDecSteps /= (uint32_t)shieldPrm[shieldId].deceleration;
+  reqDecSteps /= 2;
+
+    if(( reqAccSteps + reqDecSteps ) > nbSteps)
+    {   
+    /* Triangular move  */
+    /* reqDecSteps = (Pos * Dec) /(Dec+Acc) */
+   
+    reqDecSteps =  ((uint32_t) shieldPrm[shieldId].deceleration * nbSteps) / (shieldPrm[shieldId].acceleration + shieldPrm[shieldId].deceleration);
+    if (reqDecSteps > 1)
+    {
+      reqAccSteps = reqDecSteps - 1;
+      if(reqAccSteps == 0)
+      {
+        reqAccSteps = 1;
+      }      
+    }
+    else
+    {
+      reqAccSteps = 0;
+    }
+    shieldPrm[shieldId].endAccPos = reqAccSteps;
+    shieldPrm[shieldId].startDecPos = reqDecSteps;
+    }
+    else
+    {    
+    /* Trapezoidal move */
+    /* accelerating phase to endAccPos */
+    /* steady phase from  endAccPos to startDecPos */
+    /* decelerating from startDecPos to stepsToTake*/
+    shieldPrm[shieldId].endAccPos = reqAccSteps;
+    shieldPrm[shieldId].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 Easyspin::ConvertPosition(uint32_t abs_position_reg)
+{
+    int32_t operation_result;
+
+  if (abs_position_reg & Easyspin_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 & Easyspin_ABS_POS_VALUE_MASK);
+        operation_result = -operation_result;
+  } 
+  else 
+  {
+        operation_result = (int32_t) abs_position_reg;
+    }
+    return operation_result;
+}
+
+/******************************************************//**
+ * @brief  Handlers of the flag interrupt which calls the user callback (if defined)
+ * @param None
+ * @retval None
+ **********************************************************/
+void Easyspin::FlagInterruptHandler(void)
+{
+  if (flagInterruptCallback != NULL)
+  {
+    /* Set isr flag */
+    isrFlag = true;
+    
+    flagInterruptCallback();
+    
+    /* Reset isr flag */
+    isrFlag = false;   
+  }
+}
+
+/******************************************************//**
+ * @brief  Sends a command without arguments to the Easyspin via the SPI
+ * @param[in] shieldId (from 0 to 2)
+ * @param[in] param Command to send 
+ * @retval None
+ **********************************************************/
+void Easyspin::SendCommand(uint8_t shieldId, uint8_t param)
+{
+  uint8_t spiIndex = numberOfShields - shieldId - 1;
+  bool itDisable = false;  
+  
+  do
+  {
+    spiPreemtionByIsr = false;
+    if (itDisable)
+    {
+      /* re-enable interrupts if disable in previous iteration */
+      flag.enable_irq();
+      itDisable = false;
+    }
+  
+    for (uint32_t i = 0; i < numberOfShields; i++)
+    {
+      spiTxBursts[3][i] = Easyspin_NOP;     
+    }
+    spiTxBursts[3][spiIndex] = param;
+    
+    /* Disable interruption before checking */
+    /* pre-emption by ISR and SPI transfers*/
+    flag.disable_irq();
+    itDisable = true;
+  } while (spiPreemtionByIsr); // check pre-emption by ISR
+
+  WriteBytes(&spiTxBursts[3][0], &spiRxBursts[3][0]); 
+  
+  /* re-enable interrupts after SPI transfers*/
+  flag.enable_irq();
+}
+
+/******************************************************//**
+ * @brief  Sets the registers of the Easyspin to their predefined values 
+ * from Easyspin_target_config.h
+ * @param[in] shieldId (from 0 to 2)
+ * @retval None
+ **********************************************************/
+void Easyspin::SetRegisterToPredefinedValues(uint8_t shieldId)
+{
+  CmdSetParam(shieldId,
+                    Easyspin_ABS_POS,
+                    0);
+  CmdSetParam(shieldId,
+                    Easyspin_EL_POS,
+                    0);
+  CmdSetParam(shieldId,
+                    Easyspin_MARK,
+                    0);
+  switch (shieldId)
+  {
+    case 0:
+      CmdSetParam(shieldId,
+                        Easyspin_TVAL,
+                        Tval_Current_to_Par(Easyspin_CONF_PARAM_TVAL_SHIELD_0));
+      CmdSetParam(shieldId,
+                        Easyspin_T_FAST,
+                        (uint8_t)Easyspin_CONF_PARAM_TOFF_FAST_SHIELD_0 |
+                        (uint8_t)Easyspin_CONF_PARAM_FAST_STEP_SHIELD_0);
+      CmdSetParam(shieldId,
+                        Easyspin_TON_MIN,
+                        Tmin_Time_to_Par(Easyspin_CONF_PARAM_TON_MIN_SHIELD_0));
+      CmdSetParam(shieldId,
+                        Easyspin_TOFF_MIN,
+                        Tmin_Time_to_Par(Easyspin_CONF_PARAM_TOFF_MIN_SHIELD_0));
+      CmdSetParam(shieldId,
+                        Easyspin_OCD_TH,
+                        Easyspin_CONF_PARAM_OCD_TH_SHIELD_0);
+      CmdSetParam(shieldId,
+                        Easyspin_STEP_MODE,
+                        (uint8_t)Easyspin_CONF_PARAM_STEP_SEL_SHIELD_0 |
+                        (uint8_t)Easyspin_CONF_PARAM_SYNC_SEL_SHIELD_0);
+      CmdSetParam(shieldId,
+                        Easyspin_ALARM_EN,
+                        Easyspin_CONF_PARAM_ALARM_EN_SHIELD_0);
+      CmdSetParam(shieldId,
+                        Easyspin_CONFIG,
+                        (uint16_t)Easyspin_CONF_PARAM_CLOCK_SETTING_SHIELD_0 |
+                        (uint16_t)Easyspin_CONF_PARAM_TQ_REG_SHIELD_0 |
+                        (uint16_t)Easyspin_CONF_PARAM_OC_SD_SHIELD_0 |
+                        (uint16_t)Easyspin_CONF_PARAM_SR_SHIELD_0 |
+                        (uint16_t)Easyspin_CONF_PARAM_TOFF_SHIELD_0);
+      break;
+    case 1:
+      CmdSetParam(shieldId,
+                        Easyspin_TVAL,
+                        Tval_Current_to_Par(Easyspin_CONF_PARAM_TVAL_SHIELD_1));
+      CmdSetParam(shieldId,
+                        Easyspin_T_FAST,
+                        (uint8_t)Easyspin_CONF_PARAM_TOFF_FAST_SHIELD_1 |
+                        (uint8_t)Easyspin_CONF_PARAM_FAST_STEP_SHIELD_1);
+      CmdSetParam(shieldId,
+                        Easyspin_TON_MIN,
+                        Tmin_Time_to_Par(Easyspin_CONF_PARAM_TON_MIN_SHIELD_1));
+      CmdSetParam(shieldId,
+                        Easyspin_TOFF_MIN,
+                        Tmin_Time_to_Par(Easyspin_CONF_PARAM_TOFF_MIN_SHIELD_1));
+      CmdSetParam(shieldId,
+                        Easyspin_OCD_TH,
+                        Easyspin_CONF_PARAM_OCD_TH_SHIELD_1);
+      CmdSetParam(shieldId,
+                        Easyspin_STEP_MODE,
+                        (uint8_t)Easyspin_CONF_PARAM_STEP_SEL_SHIELD_1 |
+                        (uint8_t)Easyspin_CONF_PARAM_SYNC_SEL_SHIELD_1);
+      CmdSetParam(shieldId,
+                        Easyspin_ALARM_EN,
+                        Easyspin_CONF_PARAM_ALARM_EN_SHIELD_1);
+      CmdSetParam(shieldId,
+                        Easyspin_CONFIG,
+                        (uint16_t)Easyspin_CONF_PARAM_CLOCK_SETTING_SHIELD_1 |
+                        (uint16_t)Easyspin_CONF_PARAM_TQ_REG_SHIELD_1 |
+                        (uint16_t)Easyspin_CONF_PARAM_OC_SD_SHIELD_1 |
+                        (uint16_t)Easyspin_CONF_PARAM_SR_SHIELD_1 |
+                        (uint16_t)Easyspin_CONF_PARAM_TOFF_SHIELD_1);
+      break;
+    case 2:
+      CmdSetParam(shieldId,
+                        Easyspin_TVAL,
+                        Tval_Current_to_Par(Easyspin_CONF_PARAM_TVAL_SHIELD_2));
+      CmdSetParam(shieldId,
+                        Easyspin_T_FAST,
+                        (uint8_t)Easyspin_CONF_PARAM_TOFF_FAST_SHIELD_2 |
+                        (uint8_t)Easyspin_CONF_PARAM_FAST_STEP_SHIELD_2);
+      CmdSetParam(shieldId,
+                        Easyspin_TON_MIN,
+                        Tmin_Time_to_Par(Easyspin_CONF_PARAM_TON_MIN_SHIELD_2));
+      CmdSetParam(shieldId,
+                        Easyspin_TOFF_MIN,
+                        Tmin_Time_to_Par(Easyspin_CONF_PARAM_TOFF_MIN_SHIELD_2));
+      CmdSetParam(shieldId,
+                        Easyspin_OCD_TH,
+                        Easyspin_CONF_PARAM_OCD_TH_SHIELD_2);
+      CmdSetParam(shieldId,
+                        Easyspin_STEP_MODE,
+                        (uint8_t)Easyspin_CONF_PARAM_STEP_SEL_SHIELD_2 |
+                        (uint8_t)Easyspin_CONF_PARAM_SYNC_SEL_SHIELD_2);
+      CmdSetParam(shieldId,
+                        Easyspin_ALARM_EN,
+                        Easyspin_CONF_PARAM_ALARM_EN_SHIELD_2);
+      CmdSetParam(shieldId,
+                        Easyspin_CONFIG,
+                        (uint16_t)Easyspin_CONF_PARAM_CLOCK_SETTING_SHIELD_2 |
+                        (uint16_t)Easyspin_CONF_PARAM_TQ_REG_SHIELD_2 |
+                        (uint16_t)Easyspin_CONF_PARAM_OC_SD_SHIELD_2 |
+                        (uint16_t)Easyspin_CONF_PARAM_SR_SHIELD_2 |
+                        (uint16_t)Easyspin_CONF_PARAM_TOFF_SHIELD_2);
+      break;
+    default: ;
+  }
+}
+
+/******************************************************//**
+ * @brief  Sets the registers of the Easyspin to their predefined values 
+ * from Easyspin_target_config.h
+ * @param[in] shieldId (from 0 to 2)
+ * @retval None
+ **********************************************************/
+void Easyspin::WriteBytes(uint8_t *pByteToTransmit, uint8_t *pReceivedByte)
+{
+  CS = 0;
+  for (uint32_t i = 0; i < numberOfShields; i++)
+  {
+    *pReceivedByte = spi.write(*pByteToTransmit);
+    pByteToTransmit++;
+    pReceivedByte++;
+  }
+  CS = 1;
+  if (isrFlag)
+  {
+    spiPreemtionByIsr = true;
+  }
+}
+
+/******************************************************//**
+ * @brief  Initialises the PWM uses by the specified shield
+ * @param[in] shieldId (from 0 to 2)
+ * @retval None
+ * @note Shield 0 uses PW1 based on timer 1 
+ * Shield 1 uses PWM 2 based on timer 2
+ * Shield 2 uses PWM3 based timer 0
+ **********************************************************/
+void Easyspin::PwmInit(uint8_t shieldId)
+{
+  switch (shieldId)
+  {
+    case 0:
+      /* PWM1 uses timer 1 */
+      /* Initialise timer by setting waveform generation mode  
+      to PWM phase and Frequency correct: mode = 8 
+      (WGM10 = 0, WGM11 = 0, WGM12 = 0, WGM13 = 1) */
+    
+      /* Stop timer1 by clearing CSS bits and set WGM13 and WGM12 */
+      //TCCR1B = 0x10;  
+       
+      /* Set WGM10 and WGM11 */
+      //TCCR1A =  0x00;  
+      
+      /*  Disable Timer1 interrupt */
+      //TIMSK1 = 0;
+      //pwm1.period_us(400);
+      //pwm1.pulsewidth_us(200);
+    
+      break;
+    case  1:
+      /* PWM2 uses timer 2 */
+      /* Initialise timer by setting waveform generation mode  
+      to PWM phase correct: mode = 5
+      (WGM0 = 1, WGM21 = 0, WGM22 = 1) */
+      
+      /* Stop timer2 by clearing CSS bits and set WGM22 */
+      //TCCR2B = 0x08;  
+       
+      /* Set WGM20 and WGM21 */
+      //TCCR2A =  0x01;  
+      
+      /*  Disable Timer2 interrupt */
+      //TIMSK2 = 0; 
+      //pwm2.period_us(500);
+      //pwm2.pulsewidth_us(100);
+      break;
+
+
+    case 2:
+      /* PWM3 uses timer 0 */
+      /* !!!!! Caution: Calling this configuration will break */
+      /* all default Arduino's timing functions as delay(),millis()... */
+      
+      /* Initialise timer by setting waveform generation mode  
+      to PWM phase correct: mode = 5
+      (WGM0 = 1, WGM21 = 0, WGM22 = 1) */
+      
+      /* Stop timer0 by clearing CSS bits and set WGM22 */
+      //TCCR0B = 0x08;  
+       
+      /* Set WGM00 and WGM01 */
+      //TCCR0A =  0x01;  
+      
+      /*  Disable Timer0 interrupt */
+      //TIMSK0 = 0;
+      //pwm3.period_ms(10);
+      //pwm3.pulsewidth_ms(1);
+      break;
+    default:
+      break;//ignore error
+  }
+}
+
+/******************************************************//**
+ * @brief  Sets the frequency of PWM1 used by shield 0
+ * @param[in] newFreq in Hz
+ * @retval None
+ * @note The frequency is directly the current speed of the shield
+ **********************************************************/
+void Easyspin::Pwm1SetFreq(uint16_t newFreq)
+{
+    pwm1.period_us(newFreq);
+    pwm1.pulsewidth_us(newFreq/2);
+}
+
+/******************************************************//**
+ * @brief  Sets the frequency of PWM2 used by shield 1
+ * @param[in] newFreq in Hz
+ * @retval None
+ * @note The frequency is directly the current speed of the shield
+ **********************************************************/
+void Easyspin::Pwm2SetFreq(uint16_t newFreq)
+{
+    pwm2.period_us(newFreq);
+    pwm2.pulsewidth_us(newFreq/2);
+}
+
+/******************************************************//**
+ * @brief  Sets the frequency of PWM3 used by shield 2
+ * @param[in] newFreq in Hz
+ * @retval None
+ * @note The frequency is directly the current speed of the shield
+ **********************************************************/
+void Easyspin::Pwm3SetFreq(uint16_t newFreq)
+{
+    pwm3.period_us(newFreq);
+    pwm3.pulsewidth_us(newFreq/2);
+}
+
+/******************************************************//**
+ * @brief  Stops the PWM uses by the specified shield
+ * @param[in] shieldId (from 0 to 2)
+ * @retval None
+ **********************************************************/
+void Easyspin::PwmStop(uint8_t shieldId)
+{
+  switch (shieldId)
+  {
+    case 0:
+    pwm1.period_us(0);
+    pwm1.pulsewidth_us(0);
+      break;
+    case  1:
+    pwm2.period_us(0);
+    pwm2.pulsewidth_us(0);
+      break;
+    case 2:
+      pwm3.write(0.0f);
+      break;
+    default:
+      break;//ignore error
+  }
+}
+
+/******************************************************//**
+ * @brief  Sets the parameters of the shield to predefined values
+ * from Easyspin_target_config.h
+ * @param None
+ * @retval None
+ **********************************************************/
+void Easyspin::SetShieldParamsToPredefinedValues(void)
+{
+  shieldPrm[0].acceleration = Easyspin_CONF_PARAM_ACC_SHIELD_0;
+  shieldPrm[0].deceleration = Easyspin_CONF_PARAM_DEC_SHIELD_0;
+  shieldPrm[0].maxSpeed = Easyspin_CONF_PARAM_MAX_SPEED_SHIELD_0;
+  shieldPrm[0].minSpeed = Easyspin_CONF_PARAM_MIN_SPEED_SHIELD_0;
+  
+  shieldPrm[1].acceleration = Easyspin_CONF_PARAM_ACC_SHIELD_1;
+  shieldPrm[1].deceleration = Easyspin_CONF_PARAM_DEC_SHIELD_1;
+  shieldPrm[1].maxSpeed = Easyspin_CONF_PARAM_MAX_SPEED_SHIELD_1;
+  shieldPrm[1].minSpeed = Easyspin_CONF_PARAM_MIN_SPEED_SHIELD_1;
+  
+  shieldPrm[2].acceleration = Easyspin_CONF_PARAM_ACC_SHIELD_2;
+  shieldPrm[2].deceleration = Easyspin_CONF_PARAM_DEC_SHIELD_2;
+  shieldPrm[2].maxSpeed = Easyspin_CONF_PARAM_MAX_SPEED_SHIELD_2;
+  shieldPrm[2].minSpeed = Easyspin_CONF_PARAM_MIN_SPEED_SHIELD_2;
+  
+  for (uint8_t i = 0; i < numberOfShields; i++)
+  {
+    SetRegisterToPredefinedValues(i);
+  }   
+}
+
+/******************************************************//**
+ * @brief Initialises the bridge parameters to start the movement
+ * and enable the power bridge
+ * @param[in] shieldId (from 0 to 2)
+ * @retval None
+ **********************************************************/
+void Easyspin::StartMovement(uint8_t shieldId)  
+{
+  /* Enable Easyspin powerstage */
+  CmdEnable(shieldId);
+
+  if (shieldPrm[shieldId].endAccPos != 0)
+  {
+    shieldPrm[shieldId].motionState = ACCELERATING;;
+  }
+  else
+  {
+    shieldPrm[shieldId].motionState = DECELERATING;    
+  }
+
+  shieldPrm[shieldId].accu = 0;
+  shieldPrm[shieldId].relativePos = 0;
+  ApplySpeed(shieldId, shieldPrm[shieldId].minSpeed);
+#ifdef _DEBUG_Easyspin
+  snprintf(EasyspinStrOut, DEBUG_BUFFER_SIZE, "Stop->Acc: speed: %u relPos: %ld\n", shieldPrm[shieldId].minSpeed, shieldPrm[shieldId].relativePos) ;
+  Serial.println(EasyspinStrOut);
+#endif        
+}
+
+/******************************************************//**
+ * @brief Converts mA in compatible values for TVAL register 
+ * @param[in] Tval
+ * @retval TVAL values
+ **********************************************************/
+inline uint8_t Easyspin::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 Easyspin::Tmin_Time_to_Par(double Tmin)
+{
+  return ((uint8_t)(((Tmin - 0.5)*2)+0.5));
+}
+
+
+
+/******************************************************//**
+ * @brief  Debug   function to get the amount of free ram
+ * @param  None
+ * @retval number of bytes of free ram
+ **********************************************************/
+#ifdef _DEBUG_Easyspin
+uint16_t GetFreeRam (void)
+{
+  extern uint16_t __heap_start, *__brkval;
+  uint16_t v;
+  return (uint16_t) &v - (__brkval == 0 ? (uint16_t) &__heap_start : (uint16_t) __brkval);
+}
+#endif