text: /*
   * FreeRTOS Common IO V0.1.1
   * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
   *
   * Permission is hereby granted, free of charge, to any person obtaining a copy of
   * this software and associated documentation files (the "Software"), to deal in
   * the Software without restriction, including without limitation the rights to
   * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
   * the Software, and to permit persons to whom the Software is furnished to do so,
   * subject to the following conditions:
   *
   * The above copyright notice and this permission notice shall be included in all
   * copies or substantial portions of the Software.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
   * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
   * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   *
   * http://aws.amazon.com/freertos
   * http://www.FreeRTOS.org
   */
  
  /**
   * @file iot_spi.c
   * @brief HAL spi implementation on STM32U5 Discovery Board
   */
  
  /* ST Board includes. */
  #include "stm32u5xx_ll_spi.h"
  #include "stm32u5xx_hal.h"
  #include "stm32u5xx_hal_spi.h"
  
  /* Main includes. */
  #include "iot_spi.h"
  
  /* Total number of SPI instances on this ST microcontroller. */
  #define IOT_SPI_BLOCKING_TIMEOUT    ( ( uint32_t ) 3000UL )
  #define IOT_SPI_CLOSED              ( ( uint8_t ) 0 )
  #define IOT_SPI_OPENED              ( ( uint8_t ) 1 )
  
  typedef struct STM32_SPI_HalContext
  {
      SPI_HandleTypeDef * pxSpi;
      IRQn_Type eIrqNum;
  } STM32_SPI_HalContext_t;
  
  typedef struct IotSPIDescriptor
  {
      STM32_SPI_HalContext_t const * pxSpiContext; /* ST Handle */
      IotSPIMasterConfig_t xConfig;                /* Master Configuration */
      IotSPICallback_t xSpiCallback;               /* Callback function */
      void * pvUserContext;                        /* User context passed in callback */
      uint8_t sOpened;                             /* Bit flags to track different states. */
  } IotSPIDescriptor_t;
  /*-----------------------------------------------------------*/
  
  extern uint32_t SystemCoreClock;
  
  static SPI_HandleTypeDef xSpiHandleMap[] =
  {
      {
          .Instance = SPI1,
          .Init =
          {
              .Mode              = SPI_MODE_MASTER,
              .Direction         = SPI_DIRECTION_2LINES,
              .DataSize          = SPI_DATASIZE_8BIT,
              .CLKPolarity       = SPI_POLARITY_LOW,
              .CLKPhase          = SPI_PHASE_1EDGE,
              .NSS               = SPI_NSS_SOFT,
              .BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2,
              .FirstBit          = SPI_FIRSTBIT_MSB,
              .TIMode            = SPI_TIMODE_DISABLE,
              .CRCCalculation    = SPI_CRCCALCULATION_DISABLE,
              .CRCPolynomial     = 7,
              .CRCLength         = SPI_CRC_LENGTH_DATASIZE,
              .NSSPMode          = SPI_NSS_PULSE_ENABLE,
          },
          .pTxBuffPtr = NULL,
          .TxXferSize = 0,
          .TxXferCount = 0,
          .RxXferSize = 0,
          .RxXferCount = 0,
      },
      {
          .Instance = SPI2,
          .Init =
          {
              .Mode              = SPI_MODE_MASTER,
              .Direction         = SPI_DIRECTION_2LINES,
              .DataSize          = SPI_DATASIZE_8BIT,
              .CLKPolarity       = SPI_POLARITY_LOW,
              .CLKPhase          = SPI_PHASE_1EDGE,
              .NSS               = SPI_NSS_SOFT,
              .BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2,
              .FirstBit          = SPI_FIRSTBIT_MSB,
              .TIMode            = SPI_TIMODE_DISABLE,
              .CRCCalculation    = SPI_CRCCALCULATION_DISABLE,
              .CRCPolynomial     = 7,
              .CRCLength         = SPI_CRC_LENGTH_DATASIZE,
              .NSSPMode          = SPI_NSS_PULSE_ENABLE,
          },
          .pTxBuffPtr = NULL,
          .TxXferSize = 0,
          .TxXferCount = 0,
          .RxXferSize = 0,
          .RxXferCount = 0,
      },
      {
          .Instance = SPI3,
          .Init =
          {
              .Mode              = SPI_MODE_MASTER,
              .Direction         = SPI_DIRECTION_2LINES,
              .DataSize          = SPI_DATASIZE_8BIT,
              .CLKPolarity       = SPI_POLARITY_LOW,
              .CLKPhase          = SPI_PHASE_1EDGE,
              .NSS               = SPI_NSS_SOFT,
              .BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2,
              .FirstBit          = SPI_FIRSTBIT_MSB,
              .TIMode            = SPI_TIMODE_DISABLE,
              .CRCCalculation    = SPI_CRCCALCULATION_DISABLE,
              .CRCPolynomial     = 7,
              .CRCLength         = SPI_CRC_LENGTH_DATASIZE,
              .NSSPMode          = SPI_NSS_PULSE_ENABLE,
          },
          .pTxBuffPtr = NULL,
          .TxXferSize = 0,
          .TxXferCount = 0,
          .RxXferSize = 0,
          .RxXferCount = 0,
      }
  };
  
  static const STM32_SPI_HalContext_t xSpiContexts[] =
  {
      {
          .pxSpi = &xSpiHandleMap[ 0 ],
          .eIrqNum = SPI1_IRQn,
      },
      {
          .pxSpi = &xSpiHandleMap[ 1 ],
          .eIrqNum = SPI2_IRQn,
      },
      {
          .pxSpi = &xSpiHandleMap[ 2 ],
          .eIrqNum = SPI3_IRQn,
      }
  };
  /*-----------------------------------------------------------*/
  
  static IotSPIDescriptor_t xSpi1 =
  {
      .pxSpiContext     = &xSpiContexts[ 0 ],
      .xConfig          =
      {
          .ulFreq       = 0,
          .eMode        = eSPIMode0,
          .eSetBitOrder = eSPIMSBFirst,
          .ucDummyValue = 0
      },
      .xSpiCallback     = NULL,
      .pvUserContext    = NULL,
      .sOpened          = IOT_SPI_CLOSED,
  };
  
  static IotSPIDescriptor_t xSpi2 =
  {
      .pxSpiContext     = &xSpiContexts[ 1 ],
      .xConfig          =
      {
          .ulFreq       = 0,
          .eMode        = eSPIMode0,
          .eSetBitOrder = eSPIMSBFirst,
          .ucDummyValue = 0
      },
      .xSpiCallback     = NULL,
      .pvUserContext    = NULL,
      .sOpened          = IOT_SPI_CLOSED,
  };
  
  static IotSPIDescriptor_t xSpi3 =
  {
      .pxSpiContext     = &xSpiContexts[ 2 ],
      .xConfig          =
      {
          .ulFreq       = 0,
          .eMode        = eSPIMode0,
          .eSetBitOrder = eSPIMSBFirst,
          .ucDummyValue = 0
      },
      .xSpiCallback     = NULL,
      .pvUserContext    = NULL,
      .sOpened          = IOT_SPI_CLOSED,
  };
  /*-----------------------------------------------------------*/
  
  static IotSPIHandle_t const pxSpis[] = { &xSpi1, &xSpi2, &xSpi3 };
  
  /*--------------------API Implementation---------------------*/
  
  IotSPIHandle_t iot_spi_open( int32_t lSpiInstance )
  {
      IotSPIHandle_t xHandle = NULL;
  
      if( ( lSpiInstance >= 0 ) && ( lSpiInstance < sizeof( pxSpis ) / sizeof( IotSPIHandle_t ) ) )
      {
          xHandle = pxSpis[ lSpiInstance ];
  
          if( xHandle->sOpened == IOT_SPI_CLOSED )
          {
              if( HAL_SPI_Init( xHandle->pxSpiContext->pxSpi ) != HAL_OK )
              {
                  xHandle = NULL;
              }
              else
              {
                  xHandle->sOpened = IOT_SPI_OPENED;
  
                  xHandle->xConfig.ulFreq = ( SystemCoreClock >> 1 ); /* Default prescaler is 2 and freq = clock / prescaler */
              }
          }
          else
          {
              xHandle = NULL;
          }
      }
  
      return xHandle;
  }
  /*-----------------------------------------------------------*/
  
  void iot_spi_set_callback( IotSPIHandle_t const pxSPIPeripheral,
                             IotSPICallback_t xCallback,
                             void * pvUserContext )
  {
      if( ( pxSPIPeripheral != NULL ) )
      {
          pxSPIPeripheral->xSpiCallback = xCallback;
          pxSPIPeripheral->pvUserContext = pvUserContext;
      }
  }
  /*-----------------------------------------------------------*/
  
  int32_t iot_spi_ioctl( IotSPIHandle_t const pxSPIPeripheral,
                         IotSPIIoctlRequest_t xSPIRequest,
                         void * const pvBuffer )
  {
      int32_t lError = IOT_SPI_INVALID_VALUE;
  
      if( ( pxSPIPeripheral != NULL ) && ( pvBuffer != NULL ) )
      {
          SPI_HandleTypeDef * pxSpi = pxSPIPeripheral->pxSpiContext->pxSpi;
  
          switch( xSPIRequest )
          {
              case eSPISetMasterConfig:
  
                  if( HAL_SPI_GetState( pxSpi ) == HAL_SPI_STATE_BUSY )
                  {
                      lError = IOT_SPI_BUS_BUSY;
                  }
                  else
                  {
                      /* NOTE: HAL API sends dummy data as the same data in the master buffer. So dummy data does not need to be set in config. */
                      if( ( ( IotSPIMasterConfig_t * ) pvBuffer )->eSetBitOrder == eSPIMSBFirst )
                      {
                          LL_SPI_SetTransferBitOrder( pxSpi->Instance, SPI_FIRSTBIT_MSB );
                      }
                      else
                      {
                          LL_SPI_SetTransferBitOrder( pxSpi->Instance, SPI_FIRSTBIT_LSB );
                      }
  
                      switch( ( ( IotSPIMasterConfig_t * ) pvBuffer )->eMode )
                      {
                          case eSPIMode0:
                              LL_SPI_SetClockPolarity( pxSpi->Instance, SPI_POLARITY_LOW );
                              LL_SPI_SetClockPhase( pxSpi->Instance, SPI_PHASE_1EDGE );
                              break;
  
                          case eSPIMode1:
                              LL_SPI_SetClockPolarity( pxSpi->Instance, SPI_POLARITY_LOW );
                              LL_SPI_SetClockPhase( pxSpi->Instance, SPI_PHASE_2EDGE );
                              break;
  
                          case eSPIMode2:
                              LL_SPI_SetClockPolarity( pxSpi->Instance, SPI_POLARITY_HIGH );
                              LL_SPI_SetClockPhase( pxSpi->Instance, SPI_PHASE_1EDGE );
                              break;
  
                          case eSPIMode3:
                              LL_SPI_SetClockPolarity( pxSpi->Instance, SPI_POLARITY_HIGH );
                              LL_SPI_SetClockPhase( pxSpi->Instance, SPI_PHASE_2EDGE );
                              break;
  
                          default:
                              break;
                      }
  
                      uint32_t sysClkTmp = SystemCoreClock;
                      uint32_t preScaler = 0;
                      uint8_t divisor = 0;
  
                      while( ( sysClkTmp > ( ( IotSPIMasterConfig_t * ) pvBuffer )->ulFreq ) && ( divisor < 7 ) )
                      {
                          divisor++;
                          sysClkTmp = ( sysClkTmp >> 1 );
                      }
  
                      preScaler = ( ( ( divisor & 0x4 ) == 0 ) ? 0x0 : SPI_CFG1_MBR_2 ) |
                                  ( ( ( divisor & 0x2 ) == 0 ) ? 0x0 : SPI_CFG1_MBR_1 ) |
                                  ( ( ( divisor & 0x1 ) == 0 ) ? 0x0 : SPI_CFG1_MBR_0 );
  
                      LL_SPI_SetBaudRatePrescaler( pxSpi->Instance, preScaler );
                      lError = IOT_SPI_SUCCESS;
                      pxSPIPeripheral->xConfig = *( IotSPIMasterConfig_t * ) pvBuffer;
                  }
  
                  break;
  
              case eSPIGetMasterConfig:
  
                  ( ( IotSPIMasterConfig_t * ) pvBuffer )->ulFreq = pxSPIPeripheral->xConfig.ulFreq;
                  ( ( IotSPIMasterConfig_t * ) pvBuffer )->eMode = pxSPIPeripheral->xConfig.eMode;
                  ( ( IotSPIMasterConfig_t * ) pvBuffer )->eSetBitOrder = pxSPIPeripheral->xConfig.eSetBitOrder;
                  ( ( IotSPIMasterConfig_t * ) pvBuffer )->ucDummyValue = pxSPIPeripheral->xConfig.ucDummyValue;
  
                  lError = IOT_SPI_SUCCESS;
  
                  break;
  
              case eSPIGetTxNoOfbytes:
  
                  *( int32_t * ) pvBuffer = ( int32_t ) ( pxSpi->TxXferSize - pxSpi->TxXferCount );
                  lError = IOT_SPI_SUCCESS;
  
                  break;
  
              case eSPIGetRxNoOfbytes:
  
                  *( int32_t * ) pvBuffer = ( int32_t ) ( pxSpi->RxXferSize - pxSpi->RxXferCount );
                  lError = IOT_SPI_SUCCESS;
  
                  break;
  
              default:
                  break;
          }
      }
  
      return lError;
  }
  /*-----------------------------------------------------------*/
  
  int32_t iot_spi_read_sync( IotSPIHandle_t const pxSPIPeripheral,
                             uint8_t * const pvBuffer,
                             size_t xBytes )
  {
      int32_t lError = IOT_SPI_SUCCESS;
  
      /* TODO: How to find a way to tell if slave is not selected */
      if( ( pxSPIPeripheral == NULL ) || ( pxSPIPeripheral->sOpened == IOT_SPI_CLOSED ) )
      {
          lError = IOT_SPI_INVALID_VALUE;
      }
      else if( ( pvBuffer == NULL ) || ( xBytes == 0 ) )
      {
          lError = IOT_SPI_INVALID_VALUE;
      }
      else
      {
          SPI_HandleTypeDef * pxSpi = pxSPIPeripheral->pxSpiContext->pxSpi;
  
          if( HAL_SPI_GetState( pxSpi ) == HAL_SPI_STATE_BUSY_RX )
          {
              lError = IOT_SPI_BUS_BUSY;
          }
          else if( HAL_SPI_Receive( pxSpi, pvBuffer, ( uint16_t ) xBytes, IOT_SPI_BLOCKING_TIMEOUT ) != HAL_OK )
          {
              lError = IOT_SPI_TRANSFER_ERROR;
          }
      }
  
      return lError;
  }
  /*-----------------------------------------------------------*/
  
  int32_t iot_spi_read_async( IotSPIHandle_t const pxSPIPeripheral,
                              uint8_t * const pvBuffer,
                              size_t xBytes )
  {
      int32_t lError = IOT_SPI_SUCCESS;
  
      /* TODO: Add case for slave not selected? */
      if( ( pxSPIPeripheral == NULL ) || ( pxSPIPeripheral->sOpened == IOT_SPI_CLOSED ) )
      {
          lError = IOT_SPI_INVALID_VALUE;
      }
      else if( ( pvBuffer == NULL ) || ( xBytes == 0 ) )
      {
          lError = IOT_SPI_INVALID_VALUE;
      }
      else
      {
          SPI_HandleTypeDef * pxSpi = pxSPIPeripheral->pxSpiContext->pxSpi;
  
          if( HAL_SPI_GetState( pxSpi ) == HAL_SPI_STATE_BUSY_RX )
          {
              lError = IOT_SPI_BUS_BUSY;
          }
          else
          {
              HAL_NVIC_SetPriority( ( IRQn_Type ) ( ( STM32_SPI_HalContext_t * ) pxSPIPeripheral->pxSpiContext )->eIrqNum, 1, 0 );
              HAL_NVIC_EnableIRQ( ( IRQn_Type ) ( ( STM32_SPI_HalContext_t * ) pxSPIPeripheral->pxSpiContext )->eIrqNum );
  
              if( HAL_SPI_Receive_IT( pxSpi, pvBuffer, ( uint16_t ) xBytes ) != HAL_OK )
              {
                  lError = IOT_SPI_TRANSFER_ERROR;
              }
          }
      }
  
      return lError;
  }
  /*-----------------------------------------------------------*/
  
  int32_t iot_spi_write_sync( IotSPIHandle_t const pxSPIPeripheral,
                              uint8_t * const pvBuffer,
                              size_t xBytes )
  {
      int32_t lError = IOT_SPI_SUCCESS;
  
      /* TODO: Add case for slave not selected? */
      if( ( pxSPIPeripheral == NULL ) || ( pxSPIPeripheral->sOpened == IOT_SPI_CLOSED ) )
      {
          lError = IOT_SPI_INVALID_VALUE;
      }
      else if( ( pvBuffer == NULL ) || ( xBytes == 0 ) )
      {
          lError = IOT_SPI_INVALID_VALUE;
      }
      else
      {
          SPI_HandleTypeDef * pxSpi = pxSPIPeripheral->pxSpiContext->pxSpi;
  
          if( HAL_SPI_GetState( pxSpi ) == HAL_SPI_STATE_BUSY_TX )
          {
              lError = IOT_SPI_BUS_BUSY;
          }
          else if( HAL_SPI_Transmit( pxSpi, pvBuffer, ( uint16_t ) xBytes, IOT_SPI_BLOCKING_TIMEOUT ) != HAL_OK )
          {
              lError = IOT_SPI_TRANSFER_ERROR;
          }
      }
  
      return lError;
  }
  /*-----------------------------------------------------------*/
  
  int32_t iot_spi_write_async( IotSPIHandle_t const pxSPIPeripheral,
                               uint8_t * const pvBuffer,
                               size_t xBytes )
  {
      int32_t lError = IOT_SPI_SUCCESS;
  
      /* TODO: Add case for slave not selected? */
      if( ( pxSPIPeripheral == NULL ) || ( pxSPIPeripheral->sOpened == IOT_SPI_CLOSED ) )
      {
          lError = IOT_SPI_INVALID_VALUE;
      }
      else if( ( pvBuffer == NULL ) || ( xBytes == 0 ) )
      {
          lError = IOT_SPI_INVALID_VALUE;
      }
      else
      {
          SPI_HandleTypeDef * pxSpi = pxSPIPeripheral->pxSpiContext->pxSpi;
  
          if( HAL_SPI_GetState( pxSpi ) == HAL_SPI_STATE_BUSY_TX )
          {
              lError = IOT_SPI_BUS_BUSY;
          }
          else
          {
              HAL_NVIC_SetPriority( ( IRQn_Type ) ( ( STM32_SPI_HalContext_t * ) pxSPIPeripheral->pxSpiContext )->eIrqNum, 1, 0 );
              HAL_NVIC_EnableIRQ( ( IRQn_Type ) ( ( STM32_SPI_HalContext_t * ) pxSPIPeripheral->pxSpiContext )->eIrqNum );
  
              if( HAL_SPI_Transmit_IT( pxSpi, pvBuffer, ( uint16_t ) xBytes ) != HAL_OK )
              {
                  lError = IOT_SPI_TRANSFER_ERROR;
              }
          }
      }
  
      return lError;
  }
  /*-----------------------------------------------------------*/
  
  int32_t iot_spi_transfer_sync( IotSPIHandle_t const pxSPIPeripheral,
                                 uint8_t * const pvTxBuffer,
                                 uint8_t * const pvRxBuffer,
                                 size_t xBytes )
  {
      int32_t lError = IOT_SPI_SUCCESS;
  
      /* TODO: Add case for slave not selected? */
      if( ( pxSPIPeripheral == NULL ) || ( pxSPIPeripheral->sOpened == IOT_SPI_CLOSED ) )
      {
          lError = IOT_SPI_INVALID_VALUE;
      }
      else if( ( pvTxBuffer == NULL ) || ( pvRxBuffer == NULL ) || ( xBytes == 0 ) )
      {
          lError = IOT_SPI_INVALID_VALUE;
      }
      else
      {
          SPI_HandleTypeDef * pxSpi = pxSPIPeripheral->pxSpiContext->pxSpi;
  
          if( HAL_SPI_GetState( pxSpi ) == HAL_SPI_STATE_BUSY_TX_RX )
          {
              lError = IOT_SPI_BUS_BUSY;
          }
          else if( HAL_SPI_TransmitReceive( pxSpi, pvTxBuffer, pvRxBuffer, ( uint16_t ) xBytes, IOT_SPI_BLOCKING_TIMEOUT ) != HAL_OK )
          {
              lError = IOT_SPI_TRANSFER_ERROR;
          }
      }
  
      return lError;
  }
  /*-----------------------------------------------------------*/
  
  int32_t iot_spi_transfer_async( IotSPIHandle_t const pxSPIPeripheral,
                                  uint8_t * const pvTxBuffer,
                                  uint8_t * const pvRxBuffer,
                                  size_t xBytes )
  {
      int32_t lError = IOT_SPI_SUCCESS;
  
      /* TODO: Add case for slave not selected? */
      if( ( pxSPIPeripheral == NULL ) || ( pxSPIPeripheral->sOpened == IOT_SPI_CLOSED ) )
      {
          lError = IOT_SPI_INVALID_VALUE;
      }
      else if( ( pvTxBuffer == NULL ) || ( pvRxBuffer == NULL ) || ( xBytes == 0 ) )
      {
          lError = IOT_SPI_INVALID_VALUE;
      }
      else
      {
          SPI_HandleTypeDef * pxSpi = pxSPIPeripheral->pxSpiContext->pxSpi;
  
          if( HAL_SPI_GetState( pxSpi ) == HAL_SPI_STATE_BUSY_TX_RX )
          {
              lError = IOT_SPI_BUS_BUSY;
          }
          else
          {
              HAL_NVIC_SetPriority( ( IRQn_Type ) ( ( STM32_SPI_HalContext_t * ) pxSPIPeripheral->pxSpiContext )->eIrqNum, 1, 0 );
              HAL_NVIC_EnableIRQ( ( IRQn_Type ) ( ( STM32_SPI_HalContext_t * ) pxSPIPeripheral->pxSpiContext )->eIrqNum );
  
              if( HAL_SPI_TransmitReceive_IT( pxSpi, pvTxBuffer, pvRxBuffer, ( uint16_t ) xBytes ) != HAL_OK )
              {
                  lError = IOT_SPI_TRANSFER_ERROR;
              }
          }
      }
  
      return lError;
  }
  /*-----------------------------------------------------------*/
  
  int32_t iot_spi_close( IotSPIHandle_t const pxSPIPeripheral )
  {
      int32_t lError = IOT_SPI_SUCCESS;
  
      if( ( pxSPIPeripheral == NULL ) || ( pxSPIPeripheral->sOpened == IOT_SPI_CLOSED ) )
      {
          lError = IOT_SPI_INVALID_VALUE;
      }
      else
      {
          SPI_HandleTypeDef * pxSpi = pxSPIPeripheral->pxSpiContext->pxSpi;
  
          if( HAL_SPI_Abort( pxSpi ) != HAL_OK )
          {
              lError = IOT_SPI_BUS_BUSY;
          }
          else
          {
              /* HAL_SPI_DeInit returns OK as long as input is not NULL. */
              HAL_SPI_DeInit( pxSpi );
              pxSPIPeripheral->sOpened = IOT_SPI_CLOSED;
          }
      }
  
      return lError;
  }
  /*-----------------------------------------------------------*/
  
  int32_t iot_spi_cancel( IotSPIHandle_t const pxSPIPeripheral )
  {
      int32_t lError = IOT_SPI_INVALID_VALUE;
  
      if( ( pxSPIPeripheral != NULL ) && ( pxSPIPeripheral->sOpened == IOT_SPI_OPENED ) )
      {
          SPI_HandleTypeDef * pxSpi = pxSPIPeripheral->pxSpiContext->pxSpi;
  
          if( HAL_SPI_GetState( pxSpi ) == HAL_SPI_STATE_READY )
          {
              lError = IOT_SPI_NOTHING_TO_CANCEL;
          }
          else if( HAL_SPI_Abort( pxSpi ) == HAL_OK )
          {
              lError = IOT_SPI_SUCCESS;
          }
      }
  
      return lError;
  }
  /*-----------------------------------------------------------*/
  
  void HAL_SPI_TxRxCpltCallback( SPI_HandleTypeDef * hspi )
  {
      if( hspi->Instance == SPI1 )
      {
          xSpi1.xSpiCallback( eSPISuccess, xSpi1.pvUserContext );
      }
      else if( hspi->Instance == SPI2 )
      {
          xSpi2.xSpiCallback( eSPISuccess, xSpi2.pvUserContext );
      }
      else if( hspi->Instance == SPI3 )
      {
          xSpi3.xSpiCallback( eSPISuccess, xSpi3.pvUserContext );
      }
  }
  /*-----------------------------------------------------------*/
  
  void HAL_SPI_TxCpltCallback( SPI_HandleTypeDef * hspi )
  {
      if( hspi->Instance == SPI1 )
      {
          xSpi1.xSpiCallback( eSPISuccess, xSpi1.pvUserContext );
      }
      else if( hspi->Instance == SPI2 )
      {
          xSpi2.xSpiCallback( eSPISuccess, xSpi2.pvUserContext );
      }
      else if( hspi->Instance == SPI3 )
      {
          xSpi3.xSpiCallback( eSPISuccess, xSpi3.pvUserContext );
      }
  }
  /*-----------------------------------------------------------*/
  
  void HAL_SPI_RxCpltCallback( SPI_HandleTypeDef * hspi )
  {
      if( hspi->Instance == SPI1 )
      {
          xSpi1.xSpiCallback( eSPISuccess, xSpi1.pvUserContext );
      }
      else if( hspi->Instance == SPI2 )
      {
          xSpi2.xSpiCallback( eSPISuccess, xSpi2.pvUserContext );
      }
      else if( hspi->Instance == SPI3 )
      {
          xSpi3.xSpiCallback( eSPISuccess, xSpi3.pvUserContext );
      }
  }
  /*-----------------------------------------------------------*/
  
  void HAL_SPI_ErrorCallback( SPI_HandleTypeDef * hspi )
  {
      if( hspi->Instance == SPI1 )
      {
          xSpi1.xSpiCallback( eSPITransferError, xSpi1.pvUserContext );
      }
      else if( hspi->Instance == SPI2 )
      {
          xSpi2.xSpiCallback( eSPITransferError, xSpi2.pvUserContext );
      }
      else if( hspi->Instance == SPI3 )
      {
          xSpi3.xSpiCallback( eSPITransferError, xSpi3.pvUserContext );
      }
  }
  /*-----------------------------------------------------------*/
  
  void SPI1_IRQHandler( void )
  {
      HAL_SPI_IRQHandler( xSpi1.pxSpiContext->pxSpi );
  }
  /*-----------------------------------------------------------*/
  
  void SPI2_IRQHandler( void )
  {
      HAL_SPI_IRQHandler( xSpi2.pxSpiContext->pxSpi );
  }
  /*-----------------------------------------------------------*/
  
  void SPI3_IRQHandler( void )
  {
      HAL_SPI_IRQHandler( xSpi3.pxSpiContext->pxSpi );
  }
  /*-----------------------------------------------------------*/
  