#include "periph_spim.h"

// #define CTRLR_CLEAR         (uint32_t)0x00000
// #define SER_CLEAR            0x1
// #define BAUDR_CLEAR          (uint16_t)0xffff
// //#define SPI_SLV_OE           (uint32_t)0x00400
// #define SPI_SS               0x1
// #define FIFO_Threshold_CLEAR (uint8_t)0xff
// #define CTRLR1_CLEAR         (uint16_t)0xffff

void SPIM_DeInit(SPIM_Type* SPIx)
{
    if (SPIx == SPIM0)
    {
        SYS_CTRL->SYS_RESET |= (1 << 12);
        SYS_CTRL->SYS_RESET &= (~(1 << 12));
        *(volatile int *)(0x40000028) &= (~(1<<8));
    }
    else if (SPIx == SPIM1)
    {
        SYS_CTRL->SYS_RESET |= (1 << 13);
        SYS_CTRL->SYS_RESET &= (~(1 << 13));
        *(volatile int *)(0x40000028) &= (~(1<<9));
    }
}
void SPIM_Cmd(SPIM_Type* SPIx,FunctionalState NewState)
{
    if (NewState != DISABLE)
    {
        /* Enable the selected SPI peripheral */
        SPIx->SSIENR |= ENABLE;
        SPIx->SER |= ENABLE;
    }
    else
    {
        /* Disable the selected SPI peripheral */
        SPIx->SER &= ~ENABLE;
        SPIx->SSIENR &= ~ENABLE;
        
    }
}

void SPIM_Init(SPIM_Type* SPIx, SPIM_InitTypeDef* SPIM_InitStruct)
{
    uint32_t tmpreg = 0;
    // RCC
    if((int)SPIx == SPIM_BASE) *(volatile int *)(0x40000028) |= (1<<8);
    else *(volatile int *)(0x40000028) |= (1<<9);

    /* Configure SPIx: direction, NSS management, first transmitted bit, BaudRate prescaler
    master/salve mode, CPOL and CPHA */
    /* Set BR bits according to SPI_BaudRatePrescaler value */
    /* Set CPOL bit according to SPI_CPOL value */
    /* Set CPHA bit according to SPI_CPHA value */
    tmpreg |= (SPIM_InitStruct->SPIM_Direction | SPIM_InitStruct->SPIM_SCPOL |   
               SPIM_InitStruct->SPIM_SCPH | SPIM_FRF_MOTOROLA_SPI | SPIM_DATA_SIZE_8BITS);
    /* Write to SPIx CTRLR0 */
    SPIx->CTRLR0 = tmpreg;
    
    //Set number of wires
    tmpreg = SPIx->SSIENR;
    tmpreg &= 0x1;
    tmpreg |= SPIM_InitStruct->SPIM_Wires;
    SPIx->SSIENR = tmpreg;
    
    //Set BaudRate prescaler
    SPIx->BAUDR = SPIM_InitStruct->SPIM_BaudRatePrescaler;//写成SPIx->BAUDR = SPIM_InitStruct->SPIM_BaudRatePrescaler << 1; ??
    
    //Set TX FIFO Threshold level
    SPIx->TXFTLR = SPIM_InitStruct->SPIM_TxFIFOThreshold;
    
    //Set RX FIFO Threshold level
    SPIx->RXFTLR = SPIM_InitStruct->SPIM_RxFIFOThreshold;
	
	// 关闭所有中断
	SPIx->IMR = 0xc0;
    
}

void SPIM_StructInit(SPIM_InitTypeDef* SPIM_InitStruct)
{
    SPIM_InitStruct->SPIM_Direction = SPIM_DIRECTION_TX_AND_RX;  
      SPIM_InitStruct->SPIM_SCPOL = SPIM_SCPOL_LOW;
      SPIM_InitStruct->SPIM_SCPH = SPIM_SCPH_MIDDLE;
      SPIM_InitStruct->SPIM_BaudRatePrescaler = 0x08;
      SPIM_InitStruct->SPIM_RxFIFOThreshold = 0x08;
      SPIM_InitStruct->SPIM_TxFIFOThreshold = 0x08;
    SPIM_InitStruct->SPIM_Wires = SPIM_WIRES_4;
}


void SPIM_RecviveLengthConfig(SPIM_Type* SPIx, uint8_t RxLen)
{
    //Set number of data frames
    SPIx->CTRLR1 = RxLen - 1;
}

void SPIM_SendData(SPIM_Type* SPIx, uint8_t Data)
{
    /* Write in the DR16 register the data to be sent */
    //while(SPI_GetFlagStatus(SPIx,SPI_Transmit_FIFO_Not_Full) == RESET);
    //if(SPI_GetFlagStatus(SPIx,SPI_Transmit_FIFO_Not_Full) != RESET)
    //{
    SPIx->DR16 = Data;
    //}
}


uint8_t SPIM_ReceiveData(SPIM_Type* SPIx)
{
    /* Return the data in the DR16 register */
    return SPIx->DR16;
}


void SPIM_DataSizeConfig(SPIM_Type* SPIx, uint32_t SPI_DataSize)
{
    /* Clear  bit */
    SPIx->CTRLR0 &= (uint32_t)~SPI_DataSize;
    /* Set new  bit value */
    SPIx->CTRLR0 |= SPI_DataSize;
}

/**
 * 检查标志位
 * param: flag: 
        #define SPIM_FLAG_DATA_COLLISION_ERROR 
        #define SPIM_FLAG_TRANSMISSION_ERROR 
        #define SPIM_FLAG_RECEIVE_FIFO_FULL 
        #define SPIM_FLAG_RECEIVE_FIFO_NOT_EMPTY
        #define SPIM_FLAG_TRANSMIT_FIFO_EMPTY 
        #define SPIM_FLAG_TRANSMIT_FIFO_NOT_FULL 
        #define SPIM_FLAG_BUSY 
 * 
 * 
 */

FlagStatus SPIM_GetUsrStatus(SPIM_Type* SPIx, uint8_t Flag)
{
    FlagStatus bitstatus = RESET;

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


/**
 * SPIM中断配置
 * param:SPIM_IT
            #define SPIM_IT_MULTI_MASTER_CONTENTION
            #define SPIM_IT_RX_FIFO_FULL 
            #define SPIM_IT_RX_FIFO_OVERFLOW
            #define SPIM_IT_RX_FIFO_UNDERFLOW 
            #define SPIM_IT_TX_FIFO_OVERFLOW 
            #define SPIM_IT_TX_FIFO_EMPTY    
            #define SPIM_IT_ALL       
 */
void SPIM_ITConfig(SPIM_Type* SPIx, uint8_t SPIM_IT, FunctionalState NewState)
{
    if (NewState != DISABLE)
    {
        /* Enable the selected SPI interrupt */
        SPIx->IMR |= SPIM_IT;
    }
    else
    {
        /* Disable the selected SPI interrupt */
        SPIx->IMR &= ~SPIM_IT;
    }
}


/**
 * SPIM中断状态
 * param:SPIM_IT:
            #define SPIM_IT_MULTI_MASTER_CONTENTION
            #define SPIM_IT_RX_FIFO_FULL 
            #define SPIM_IT_RX_FIFO_OVERFLOW
            #define SPIM_IT_RX_FIFO_UNDERFLOW 
            #define SPIM_IT_TX_FIFO_OVERFLOW 
            #define SPIM_IT_TX_FIFO_EMPTY    
            #define SPIM_IT_ALL       
 */
ITStatus SPIM_GetITStatus(SPIM_Type* SPIx, uint8_t SPIM_IT)
{
    ITStatus bitstatus = RESET;
    uint8_t itpos = 0;

    itpos = SPIx->ISR & SPIM_IT;
    /* Check the status of the specified SPI interrupt */
    if (itpos != RESET)
    {
        /* SPI_IT is set */
        bitstatus = SET;
    }
    else
    {
        /* SPI_IT is reset */
        bitstatus = RESET;
    }
    /* Return the SPI_IT status */
    return bitstatus;
}

/**
 * SPI收发模式设置
 * param: SPIM_Direction:
            #define SPIM_DIRECTION_TX_AND_RX  //全双工模式；发一字节，同时收一字节  
            #define SPIM_DIRECTION_TX_ONLY   //仅发送
            #define SPIM_DIRECTION_RX_ONLY   //写TxFIFO触发收一字节，实际不发送
 */
void SPIM_Direction_Switch(SPIM_Type* SPIx, uint32_t SPIM_Direction)
{
    //change spi direction
    /* Clear  bit */
    SPIx->CTRLR0 &= (uint32_t)(~0x700);
    /* Set new  bit value */
    SPIx->CTRLR0 |= SPIM_Direction;
}

//void SPIM_Direction_Switch(SPIM_Type* SPIx, uint32_t SPIM_Direction, uint8_t RxLen)
//{
//    //SPI Disable
//    SPIM_Cmd(SPIx, DISABLE);
//    //change spi direction
//    /* Clear  bit */
//    SPIx->CTRLR0 &= (uint32_t)(~0x700);
//    /* Set new  bit value */
//    SPIx->CTRLR0 |= SPIM_Direction;
//    //Set the number of received data by spi;only valid in rx only mode
//    SPIM_RecviveLengthConfig(SPIx, RxLen);
//    //SPI Enable
//    SPIM_Cmd(SPIx, ENABLE);
//}
