/******************************************************************************
*@file  : spl_spi.c
*@brief : SPI SPL module driver
******************************************************************************/

#include "spl_spi.h"

/* SPI registers Masks */
#define CTL_CLEAR_MASK            ((uint32_t)0x1FFE82)

/**
  * @brief  Deinitializes the SPIx peripheral registers to their default
  *         reset values.
  * @param  SPIx: where x can be 1, 2 ... to select the SPI peripheral.
  * @retval None
  */
void SPI_DeInit(SPI_TypeDef* SPIx)
{
    /* Check the parameters */
    assert_param(IS_SPI_ALL_PERIPH(SPIx));

    if (SPIx == SPI1)
    {
        __RCC_SPI1_RESET();
    }
    else if (SPIx == SPI2)
    {
        __RCC_SPI2_RESET();
    }
    else{      
        if (SPIx == SPI3)
        {
            __RCC_SPI3_RESET();
        }  
    }
}

/**
  * @brief  Initializes the SPIx peripheral according to the specified 
  *         parameters in the SPI_InitStruct.
  * @param  SPIx: where x can be 1, 2 ... to select the SPI peripheral.
  * @param  SPI_InitStruct: pointer to a SPI_InitTypeDef structure that
  *         contains the configuration information for the specified SPI peripheral.
  * @retval None
  */
void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct)
{
    uint16_t tmpreg = 0;

    /* check the parameters */
    assert_param(IS_SPI_ALL_PERIPH(SPIx));
    assert_param(IS_SPI_MODE(SPI_InitStruct->SPI_Mode));
    assert_param(IS_SPI_FIRST_BIT(SPI_InitStruct->First_Bit));
    
    tmpreg = SPIx->CTL;
    
    tmpreg &= CTL_CLEAR_MASK;

    tmpreg |= (uint32_t)(SPI_InitStruct->SPI_Mode | SPI_InitStruct->SPI_Work_Mode | \
                                  SPI_InitStruct->X_Mode | SPI_InitStruct->First_Bit);

    SPIx->CTL = tmpreg;
    
    /* Automatic change direction */
    SPIx->CTL |= (SPI_CTL_IO_MODE);
    
    if(SPI_InitStruct->SPI_Mode == SPI_MODE_SLAVE)
    {
        assert_param(IS_SPI_SLAVE_SWCS_MANAGMENT(SPI_InitStruct->Slave_SWCS));        
        assert_param(IS_SPI_SLAVE_CS_FILSTER(SPI_InitStruct->Slave_CS_Fliter));
        assert_param(IS_SPI_SLAVE_SCLK_FILSTER(SPI_InitStruct->Slave_SCLK_Fliter));
        
        MODIFY_REG(SPIx->CTL, SPI_CTL_CS_FILTER, SPI_InitStruct->Slave_CS_Fliter);
        
        MODIFY_REG(SPIx->CTL, SPI_CTL_SFILTER, SPI_InitStruct->Slave_SCLK_Fliter);
        
        if(SPI_InitStruct->Slave_SWCS == SPI_SLAVE_SWCS_ENABLE)
        {
            SET_BIT(SPIx->CTL, SPI_CTL_SWCS_EN);            
        }
        else
        {
            CLEAR_BIT(SPIx->CTL, SPI_CTL_SWCS_EN); 
        }
                
        SPIx->BATCH = (SPIx->BATCH & (~0x000FFFFFU)) | (1 << 0);
        
        SPIx->TX_CTL |= SPI_TX_CTL_MODE | (0x88 << 8);  // dummy data = 0x88
        
        SPIx->CTL |= SPI_CTL_SLAVE_EN;
    }
    else
    {
        assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_InitStruct->BaudRate_Prescaler));
        assert_param(IS_SPI_MASTER_SSHIFT(SPI_InitStruct->Master_SShift));

        /* Set SPI BaudRate Prescaler */
        SPIx->BAUD = ((SPIx->BAUD) & (~0x0000FFFF)) | (SPI_InitStruct->BaudRate_Prescaler);
        
        MODIFY_REG(SPIx->RX_CTL, SPI_RX_CTL_SSHIFT, SPI_InitStruct->Master_SShift);
    }
    
    /* Disable All Interrupt */
    SPIx->IE = 0x00000000;
}

/**
  * @brief  Fills each SPI_InitStruct member with its default value.
  * @param  SPI_InitStruct: pointer to a SPI_InitTypeDef structure which will be initialized.
  * @retval None
  */
void SPI_StructInit(SPI_InitTypeDef* SPI_InitStruct)
{
/*--------------- Reset SPI init structure parameters values -----------------*/
    /* initialize the SPI_Mode member */
    SPI_InitStruct->SPI_Mode = SPI_MODE_MASTER;
    /* Initialize the SPI_Work_Mode(CPOL & CPHA) member */
    SPI_InitStruct->SPI_Work_Mode = SPI_WORK_MODE_0;
    /* Initialize the SPI_X_Mode member */
    SPI_InitStruct->X_Mode = SPI_1X_MODE;      
    /* Initialize the SPI_FirstBit member */
    SPI_InitStruct->First_Bit = SPI_FIRSTBIT_MSB;
    /* Initialize the SPI_BaudRatePrescaler member */
    SPI_InitStruct->BaudRate_Prescaler = SPI_BAUDRATE_PRESCALER_4;
    /* Initialize the Slave_SWCS member */
    SPI_InitStruct->Slave_SWCS = SPI_SLAVE_SWCS_DISABLE;
    /* Initialize the Slave_CS_Filter member */
    SPI_InitStruct->Slave_CS_Fliter = SPI_SLAVE_CS_FILTER_DISABLE;
    /* Initialize the Slave_SCLK_Filter member */
    SPI_InitStruct->Slave_SCLK_Fliter = SPI_SLAVE_SCLK_FILTER_DISABLE;
    /* Initialize the Master_SShift member */
    SPI_InitStruct->Master_SShift = SPI_MASTER_SSHIFT_NONE;
}


void SPI_Set_BaudRatePrescaler(SPI_TypeDef* SPIx, uint32_t  BaudRate_Prescaler)
{
    /* Set SPI BaudRate Prescaler */
    SPIx->BAUD = ((SPIx->BAUD) & (~0x0000FFFF)) | BaudRate_Prescaler;
}

/**
  * @brief  Enables or disables the SPIx transmit.
  * @param  SPIx: where x can be 1, 2 ... to select the SPI peripheral.
  * @param  NewState: new state of the selected SPI transmit.
  *   This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void SPI_TxCmd(SPI_TypeDef* SPIx, FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_SPI_ALL_PERIPH(SPIx));
    assert_param(IS_FUNCTIONAL_STATE(NewState));

    if (NewState != DISABLE)
    {
        /* Enable the selected SPI transmit */
        SPIx->TX_CTL |= SPI_TX_CTL_EN;
    }
    else
    {
        /* Disable the selected SPI transmit */
        SPIx->TX_CTL &= ~SPI_TX_CTL_EN;
    }
}

/**
  * @brief  Enables or disables the SPIx recieve.
  * @param  SPIx: where x can be 1, 2 ... to select the SPI peripheral.
  * @param  NewState: new state of the selected SPI recieve.
  *   This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void SPI_RxCmd(SPI_TypeDef* SPIx, FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_SPI_ALL_PERIPH(SPIx));
    assert_param(IS_FUNCTIONAL_STATE(NewState));

    if (NewState != DISABLE)
    {
        /* Enable the selected SPI recieve */
        SPIx->RX_CTL |= SPI_RX_CTL_EN;
    }
    else
    {
        /* Disable the selected SPI recieve */
        SPIx->RX_CTL &= ~SPI_RX_CTL_EN;
    }
}


/**
  * @brief  Configures SWCS state for the selected SPI slave.
  * @param  SPIx: where x can be 1, 2 ... to select the SPI peripheral.
  * @param  Slave_SWCS_State: specifies the Slave SWCS state.
  *          This parameter can be one of the following values:
  *            @arg SPI_Slave_SWCS_Set:   Set CS pin internally
  *            @arg SPI_Slave_SWCS_Reset: Reset CS pin internally
  * @retval None
  * @note   This funcion is useful only when SWCS management is enabled.
  */
void SPI_Slave_SWCS_Config(SPI_TypeDef* SPIx, uint32_t Slave_SWCS_State)
{
  /* Check the parameters */
  assert_param(IS_SPI_ALL_PERIPH(SPIx));
  assert_param(IS_SPI_SLAVE_SWCS_STATE(Slave_SWCS_State));
  if (Slave_SWCS_State != SPI_Slave_SWCS_Reset)
  {
    /* Set NSS pin internally by software */
    SPIx->CTL |= SPI_Slave_SWCS_Set;
  }
  else
  {
    /* Reset NSS pin internally by software */
    SPIx->CTL &= SPI_Slave_SWCS_Reset;
  }
}

/**
  * @brief  Enables or disables the specified SPI interrupts.
  * @param  SPIx: where x can be 1, 2 ... to select the SPI peripheral.
  * @param  SPI_IT: specifies the SPI interrupt source to be enabled or disabled. 
  *   This parameter can be one of the following values:
  *     @arg SPI_IE_BATCH_DONE_EN:      Batch done interrupt 
  *     @arg SPI_IE_TX_FIFO_EMPTY_EN:   TX Fifo empty interrupt
  *     @arg SPI_IE_TX_FIFO_FULL_EN:    TX Fifo full interrupt
  *     @arg SPI_IE_RX_FIFO_EMPTY_EN:   RX Fifo empty interrupt
  *     @arg SPI_IE_RX_FIFO_FULL_EN:    RX Fifo full interrupt
  *     @arg SPI_IE_TX_FIFO_HALF_EMPTY_EN: TX Fifo half empty interrupt
  *     @arg SPI_IE_TX_FIFO_HALF_FULL_EN:  TX Fifo half full interrupt
  *     @arg SPI_IE_RX_FIFO_HALF_EMPTY_EN: RX Fifo half empty interrupt
  *     @arg SPI_IE_RX_FIFO_HALF_FULL_EN:  RX Fifo half full interrupt
  *     @arg SPI_IE_CS_POS_EN:             CS flag interrupt
  *     @arg SPI_IE_RX_FIFO_NOT_EMPTY_EN:  RX Fifo not empty interrupt
  *     @arg SPI_IE_RX_FIFO_EMPTY_OVERFLOW_EN: RX Fifo empty overflow interrupt
  *     @arg SPI_IE_RX_FIFO_FULL_OVERFLOW_EN:  RX Fifo full overflow interrupt
  *     @arg SPI_IE_TX_BATCH_DONE_EN: Transmit batch done interrupt
  *     @arg SPI_IE_RX_BATCH_DONE_EN: Recieve batch done interrupt
  * @param  NewState: new state of the specified SPI interrupt.
  *   This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void SPI_ITConfig(SPI_TypeDef* SPIx, uint32_t SPI_IT, FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_SPI_ALL_PERIPH(SPIx));
    assert_param(IS_FUNCTIONAL_STATE(NewState));
    assert_param(IS_SPI_CONFIG_IT(SPI_IT));

    if (NewState != DISABLE)
    {
        /* Enable the selected SPI interrupt */
        SPIx->IE |= SPI_IT;
    }
    else
    {
        /* Disable the selected SPI interrupt */
        SPIx->IE &= (uint32_t)~SPI_IT;
    }
}

/**
  * @brief  Get the specified SPI interrupts is enabled or not.
  * @param  SPIx: where x can be 1, 2 ... to select the SPI peripheral.
  * @param  SPI_IT: specifies the SPI interrupt source to be read. 
  *   This parameter can be one of the following values:
  *     @arg SPI_IE_BATCH_DONE_EN:      Batch done interrupt 
  *     @arg SPI_IE_TX_FIFO_EMPTY_EN:   TX Fifo empty interrupt
  *     @arg SPI_IE_TX_FIFO_FULL_EN:    TX Fifo full interrupt
  *     @arg SPI_IE_RX_FIFO_EMPTY_EN:   RX Fifo empty interrupt
  *     @arg SPI_IE_RX_FIFO_FULL_EN:    RX Fifo full interrupt
  *     @arg SPI_IE_TX_FIFO_HALF_EMPTY_EN: TX Fifo half empty interrupt
  *     @arg SPI_IE_TX_FIFO_HALF_FULL_EN:  TX Fifo half full interrupt
  *     @arg SPI_IE_RX_FIFO_HALF_EMPTY_EN: RX Fifo half empty interrupt
  *     @arg SPI_IE_RX_FIFO_HALF_FULL_EN:  RX Fifo half full interrupt
  *     @arg SPI_IE_CS_POS_EN:             CS flag interrupt
  *     @arg SPI_IE_RX_FIFO_NOT_EMPTY_EN:  RX Fifo not empty interrupt
  *     @arg SPI_IE_RX_FIFO_EMPTY_OVERFLOW_EN: RX Fifo empty overflow interrupt
  *     @arg SPI_IE_RX_FIFO_FULL_OVERFLOW_EN:  RX Fifo full overflow interrupt
  *     @arg SPI_IE_TX_BATCH_DONE_EN: Transmit batch done interrupt
  *     @arg SPI_IE_RX_BATCH_DONE_EN: Recieve batch done interrupt
  * @retval The interrupt flag of SPI_IT (SET or RESET).
  */
FlagStatus SPI_ITGet(SPI_TypeDef* SPIx, uint32_t SPI_IT)
{
    FlagStatus bitstatus = RESET;
    /* Check the parameters */
    assert_param(IS_SPI_ALL_PERIPH(SPIx));
    assert_param(IS_SPI_CONFIG_IT(SPI_IT));

    /* Check the specified SPI interrupts flag */
    if ((SPIx->IE & SPI_IT) != (uint32_t)RESET)
    {
        /* SPI_FLAG is set */
        bitstatus = SET;
    }
    else
    {
        /* SPI_FLAG is reset */
        bitstatus = RESET;
    }
    /* Return the SPI_FLAG status */
    return  bitstatus;
}

/**
  * @brief  Set SPI DMA FIFO level.
  * @param  SPIx: where x can be 1, 2 ... to select the SPI peripheral.
  * @param  Fifo_level: This parameter can be a value of. 
  *   This parameter can be one of the following values:
  *     @arg SPI_RX_CTL_DMA_LEVEL:   15 bytes dma trig mode.
  *     @arg SPI_RX_CTL_DMA_LEVEL_0: 1 byte dma trig mode.
  *     @arg SPI_RX_CTL_DMA_LEVEL_1: 2 bytes dma trig mode.
  *     @arg SPI_RX_CTL_DMA_LEVEL_2: 4 bytes dma trig mode.
  *     @arg SPI_RX_CTL_DMA_LEVEL_3: 8 bytes dma trig mode.
  * @retval None
  */
void SPI_DMA_RXFIFO_Level_Set(SPI_TypeDef* SPIx, uint32_t Fifo_level)
{
    /* Check the parameters */
    assert_param(IS_SPI_ALL_PERIPH(SPIx));
    
    /* Set SPI DMA FIFO level */
    SPIx->RX_CTL |= Fifo_level;
}

/**
  * @brief  Set SPI DMA FIFO level.
  * @param  SPIx: where x can be 1, 2 ... to select the SPI peripheral.
  * @param  Fifo_level: This parameter can be a value of. 
  *   This parameter can be one of the following values:
  *     @arg SPI_TX_CTL_DMA_LEVEL:   15 bytes dma trig mode.
  *     @arg SPI_TX_CTL_DMA_LEVEL_0: 1 byte dma trig mode.
  *     @arg SPI_TX_CTL_DMA_LEVEL_1: 2 bytes dma trig mode.
  *     @arg SPI_TX_CTL_DMA_LEVEL_2: 4 bytes dma trig mode.
  *     @arg SPI_TX_CTL_DMA_LEVEL_3: 8 bytes dma trig mode.
  * @retval None
  */
void SPI_DMA_TXFIFO_Level_Set(SPI_TypeDef* SPIx, uint32_t Fifo_level)
{
    /* Check the parameters */
    assert_param(IS_SPI_ALL_PERIPH(SPIx));
    
    /* Set SPI DMA FIFO level */
    SPIx->TX_CTL |= Fifo_level;
}

/**
  * @brief  Enables or disables the SPIx DMA interface.
  * @param  SPIx: where x can be 1, 2 ... to select the SPI peripheral.
  * @param  SPI_DMAReq: specifies the SPI DMA transfer request to be enabled or disabled. 
  *   This parameter can be any combination of the following values:
  *     @arg SPI_DMAReq_TX: Tx buffer DMA transfer request
  *     @arg SPI_DMAReq_RX: Rx buffer DMA transfer request
  * @param  NewState: new state of the selected SPI DMA transfer request.
  *   This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void SPI_DMACmd(SPI_TypeDef* SPIx, uint16_t SPI_DMAReq, FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_SPI_ALL_PERIPH(SPIx));
    assert_param(IS_FUNCTIONAL_STATE(NewState));
    assert_param(IS_SPI_DMAREQ(SPI_DMAReq));
    if (NewState != DISABLE)
    {
        /* Enable the selected SPI DMA TX requests */
        if(SPI_DMAReq & SPI_DMAReq_TX)
            SPIx->TX_CTL |= SPI_TX_CTL_DMA_REQ_EN;
        
        /* Enable the selected SPI DMA RX requests */
        if(SPI_DMAReq & SPI_DMAReq_RX)
            SPIx->RX_CTL |= SPI_RX_CTL_DMA_REQ_EN;
    }
    else
    {
        /* Disable the selected SPI DMA TX requests */
        if(SPI_DMAReq & SPI_DMAReq_TX)
            SPIx->TX_CTL &= (~SPI_TX_CTL_DMA_REQ_EN);
        
        /* Disable the selected SPI DMA RX requests */
        if(SPI_DMAReq & SPI_DMAReq_RX)
            SPIx->RX_CTL &= (~SPI_RX_CTL_DMA_REQ_EN);
    }
}    

/**
  * @brief  Transmits a Data through the SPIx peripheral.
  * @param  SPIx: where x can be 1, 2 ... to select the SPI peripheral.
  * @param  Data : Data to be transmitted.
  * @retval None
  */
void SPI_SendData(SPI_TypeDef* SPIx, uint8_t Data)
{
    /* Check the parameters */
    assert_param(IS_SPI_ALL_PERIPH(SPIx));

    /* Write in the DR register the data to be sent */
    SPIx->DAT = Data;
}

/**
  * @brief  Returns the most recent received data by the SPIx peripheral. 
  * @param  SPIx: where x can be 1, 2 ... to select the SPI peripheral.
  * @retval The value of the received data.
  */
uint8_t SPI_ReceiveData(SPI_TypeDef* SPIx)
{
    /* Check the parameters */
    assert_param(IS_SPI_ALL_PERIPH(SPIx));

    /* Return the data in the DR register */
    return (uint8_t)SPIx->DAT;
}

/**
  * @brief  Enables or disables the SS output for the selected SPI.
  * @param  SPIx: where x can be 1, 2 ... to select the SPI peripheral.
  * @param  NewState: new state of the SPIx SS output. 
  *   This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void SPI_SSOutputCmd(SPI_TypeDef* SPIx, FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_SPI_ALL_PERIPH(SPIx));
    assert_param(IS_FUNCTIONAL_STATE(NewState));
    if (NewState != DISABLE)
    {
        /* Enable the selected SPI SS output */
        SPIx->CS |= SPI_CS_CS0;
    }
    else
    {
        /* Disable the selected SPI SS output */
        SPIx->CS &= ~SPI_CS_CS0;
    }
}

/**
  * @brief  SPI Wire Config.
  * @param  SPIx: where x can be 1, 2 ... to select the SPI peripheral.
  * @param  X_Mode: This parameter can be a value of @ref X_MODE. 
  *   This parameter can be one of the following values:
  *     @arg SPI_1X_MODE: 1 wire mode.
  *     @arg SPI_2X_MODE: 2 wire mode.
  *     @arg SPI_4X_MODE: 4 wire mode.
  * @retval None
  */
void SPI_Wire_Config(SPI_TypeDef* SPIx, uint32_t X_Mode)
{
    /* Check the parameters */
    assert_param(IS_SPI_ALL_PERIPH(SPIx));
    
    /* Set SPI X_Mode */
    SPIx->CTL = ((SPIx->CTL) & (~SPI_CTL_X_MODE)) | X_Mode;
}

/**
  * @brief  Write a number in the BATCH register through the SPIx peripheral.
  * @param  SPIx: where x can be 1, 2 ... to select the SPI peripheral.
  * @param  number : number to be writed to the register.
  * @retval None
  */
void SPI_WriteBatch(SPI_TypeDef* SPIx, uint32_t number)
{
    /* Check the parameters */
    assert_param(IS_SPI_ALL_PERIPH(SPIx));

    /* Write in the BATCH register the number */
    SPIx->BATCH = number;
}

/**
  * @brief  Returns the batch number by the SPIx peripheral. 
  * @param  SPIx: where x can be 1, 2 ... to select the SPI peripheral.
  * @retval The value of the batch number.
  */
uint32_t SPI_ReadBatch(SPI_TypeDef* SPIx)
{
    /* Check the parameters */
    assert_param(IS_SPI_ALL_PERIPH(SPIx));

    /* Return the number in the BATCH register */
    return SPIx->BATCH;
}

/**
  * @brief  Clear the SPI Tx FIFO.
  * @param  SPIx: where x can be 1, 2 ... to select the SPI peripheral.
  * @retval None
  */
void SPI_ClearTxFifo(SPI_TypeDef* SPIx)
{
    /* Check the parameters */
    assert_param(IS_SPI_ALL_PERIPH(SPIx));

    /* Clear the TX FIFO */
    SET_BIT(SPIx->TX_CTL, SPI_TX_CTL_FIFO_RESET);
    CLEAR_BIT(SPIx->TX_CTL, SPI_TX_CTL_FIFO_RESET);
}

/**
  * @brief  Clear the SPI Rx FIFO.
  * @param  SPIx: where x can be 1, 2 ... to select the SPI peripheral.
  * @retval None
  */
void SPI_ClearRxFifo(SPI_TypeDef* SPIx)
{
    /* Check the parameters */
    assert_param(IS_SPI_ALL_PERIPH(SPIx));

    /* Clear the RX FIFO */
    SET_BIT(SPIx->RX_CTL, SPI_RX_CTL_FIFO_RESET);
    CLEAR_BIT(SPIx->RX_CTL, SPI_RX_CTL_FIFO_RESET);
}

/**
  * @brief  Checks whether the specified SPI flag is set or not.
  * @param  SPIx: where x can be 1, 2 ... to select the SPI peripheral.
  * @param  SPI_FLAG: specifies the SPI flag to check. 
  *   This parameter can be one of the following values:
  *     @arg SPI_STATUS_TX_BUSY: Tx busy flag
  *     @arg SPI_STATUS_BATCH_DONE: Batch transfer completed flag
  *     @arg SPI_STATUS_TX_FIFO_EMPTY: Tx Fifo empty flag
  *     @arg SPI_STATUS_TX_FIFO_FULL: Tx Fifo full flag
  *     @arg SPI_STATUS_RX_FIFO_EMPTY: Rx Fifo empty flag
  *     @arg SPI_STATUS_RX_FIFO_FULL: Rx Fifo full flag
  *     @arg SPI_STATUS_TX_FIFO_HALF_EMPTY: Tx Fifo half empty flag
  *     @arg SPI_STATUS_TX_FIFO_HALF_FULL: Tx Fifo half full flag
  *     @arg SPI_STATUS_RX_FIFO_HALF_EMPTY: Rx Fifo half empty flag
  *     @arg SPI_STATUS_RX_FIFO_HALF_FULL: Rx Fifo half full flag
  *     @arg SPI_STATUS_CS_POS_FLG: CS signal flag
  *     @arg SPI_STATUS_RX_FIFO_NOT_EMPTY: Rx Fifo NOT empty flag
  *     @arg SPI_STATUS_RX_FIFO_EMPTY_OVERFLOW: Rx Fifo empty overflow flag
  *     @arg SPI_STATUS_RX_FIFO_FULL_OVERFLOW: Rx Fifo full overflow flag
  *     @arg SPI_STATUS_TX_BATCH_DONE: Transmit batch done flag
  *     @arg SPI_STATUS_RX_BATCH_DONE: Recieve batch done flag
  * @retval The new state of SPI_FLAG (SET or RESET).
  */
FlagStatus SPI_GetFlagStatus(SPI_TypeDef* SPIx, uint32_t SPI_FLAG)
{
    FlagStatus bitstatus = RESET;
    /* Check the parameters */
    assert_param(IS_SPI_ALL_PERIPH(SPIx));
    assert_param(IS_SPI_GET_FLAG(SPI_FLAG));
    /* Check the status of the specified SPI flag */
    if ((SPIx->STATUS & SPI_FLAG) != (uint32_t)RESET)
    {
        /* SPI_FLAG is set */
        bitstatus = SET;
    }
    else
    {
        /* SPI_FLAG is reset */
        bitstatus = RESET;
    }
    /* Return the SPI_FLAG status */
    return  bitstatus;
}

/**
  * @brief  Clears the SPIx Status flag.
  * @param  SPIx: where x can be 1, 2 ... to select the SPI peripheral.
  * @param  SPI_FLAG: specifies the SPI flag to check. 
  *   This parameter can be one of the following values:
  *     @arg SPI_CLEAR_BATCH_DONE: Clear batch done flag
  *     @arg SPI_CLEAR_CS_POS: Clear cs rising edge flag
  * @retval None
  */
void SPI_ClearFlag(SPI_TypeDef* SPIx, uint32_t SPI_FLAG)
{
    /* Check the parameters */
    assert_param(IS_SPI_ALL_PERIPH(SPIx));
    assert_param(IS_SPI_CLEAR_FLAG(SPI_FLAG));

    /* Clear the selected SPI flag */
    SPIx->STATUS = SPI_FLAG;
}

/**
  * @brief  Checks whether the specified SPIx interrupt has occurred or not.
  * @param  SPIx: where x can be 1, 2 ... to select the SPI peripheral.
  * @param  SPI_FLAG: specifies the SPI flag to check. 
  *   This parameter can be one of the following values:
  *     @arg SPI_STATUS_TX_BUSY: Tx busy flag
  *     @arg SPI_STATUS_BATCH_DONE: Batch transfer completed flag
  *     @arg SPI_STATUS_TX_FIFO_EMPTY: Tx Fifo empty flag
  *     @arg SPI_STATUS_TX_FIFO_FULL: Tx Fifo full flag
  *     @arg SPI_STATUS_RX_FIFO_EMPTY: Rx Fifo empty flag
  *     @arg SPI_STATUS_RX_FIFO_FULL: Rx Fifo full flag
  *     @arg SPI_STATUS_TX_FIFO_HALF_EMPTY: Tx Fifo half empty flag
  *     @arg SPI_STATUS_TX_FIFO_HALF_FULL: Tx Fifo half full flag
  *     @arg SPI_STATUS_RX_FIFO_HALF_EMPTY: Rx Fifo half empty flag
  *     @arg SPI_STATUS_RX_FIFO_HALF_FULL: Rx Fifo half full flag
  *     @arg SPI_STATUS_CS_POS_FLG: CS signal flag
  *     @arg SPI_STATUS_RX_FIFO_NOT_EMPTY: Rx Fifo NOT empty flag
  *     @arg SPI_STATUS_RX_FIFO_EMPTY_OVERFLOW: Rx Fifo empty overflow flag
  *     @arg SPI_STATUS_RX_FIFO_FULL_OVERFLOW: Rx Fifo full overflow flag
  *     @arg SPI_STATUS_TX_BATCH_DONE: Transmit batch done flag
  *     @arg SPI_STATUS_RX_BATCH_DONE: Recieve batch done flag
  * @retval The new state of SPI_FLAG (SET or RESET).
  */
ITStatus SPI_GetITStatus(SPI_TypeDef* SPIx, uint32_t SPI_IT)
{
    FlagStatus bitstatus = RESET;
    uint32_t iesets;
    uint32_t isrflags;
    
    /* Check the parameters */
    assert_param(IS_SPI_ALL_PERIPH(SPIx));
    assert_param(IS_SPI_GET_FLAG(SPI_IT));
    
    iesets = SPIx->IE;
    isrflags = SPIx->STATUS;
    isrflags &= iesets;
    
    return ((isrflags & SPI_IT) == SPI_IT)? SET : RESET;

}

/**
  * @brief  Clears the SPIx IT Status flag(interrupt pending bit).
  * @param  SPIx: where x can be 1, 2 ... to select the SPI peripheral.
  * @param  SPI_FLAG: specifies the SPI flag to check. 
  *   This parameter can be one of the following values:
  *     @arg SPI_CLEAR_BATCH_DONE: Clear batch done flag
  *     @arg SPI_CLEAR_CS_POS: Clear cs rising edge flag
  * @retval None
  */
void SPI_ClearITPendingBit(SPI_TypeDef* SPIx, uint32_t SPI_IT)
{
    SPI_ClearFlag(SPIx, SPI_IT);
}


